This document accompanies my PhD thesis titled “Enhancing analysis and interpretation workflows for transcriptome data with an interactive R Bioconductor toolkit”. The document will follow all the analysis and steps documented in my PhD thesis in Section 3.3.

1 About the data

The data illustrated in this document is documented in detail in Section 3.3.1 of my PhD thesis.

The datasets shown is an RNA-seq dataset, available at the Gene Expression Omnibus under the accession code GSE130842.

The data represents a mouse data set of 56 different samples isolated from various murine tissues. In this analysis, I will focus in the Klrg1-negative Nfil3(GFP)-negative Tregs and Klrg1-positive Nfil3(GFP)-positive Tregs samples as discussed with the original authors of the manuscript (Delacher et al. 2020). To analyse the data, the count data was downloaded from the Gene Expression Omnibus (https://www.ncbi.xyz/geo/query/acc.cgi?acc=GSE130842). The count data can be found in file “GSE130842_Count_table_Delacher_et_al_2019.xlsx”. Additionally, a metadata file was set up, containing the sample names, conditions and replicate numbers following the information of the GEO entry. This is the file named “GSE130842_Count_table_Delacher_et_al_2019.csv”

The workflow shown in this document will follow the steps described in our manuscript “Interactive and Reproducible Workflows for Exploring and Modeling RNA-seq Data with pcaExplorer, Ideal, and GeneTonic” (Ludt et al. 2022).

2 Loading required packages

First, load the packages required to perform all the analytic steps presented in this document.

library("DESeq2")
library("topGO")
library("pcaExplorer")
library("ideal")
library("GeneTonic")
library("apeglm")
library("dplyr")
library("readxl")
library("GeDi")
library("org.Mm.eg.db")
library("utils")
library("ComplexHeatmap")
library("readxl")
library("ggplot2")
library("dplyr")
library("forcats")
library("visNetwork")

3 Data processing

First, the data will be preprocessed and saved as an DESeqDataSet object, as described in Section 3.3.1 of my thesis.

# Read the gene expression count data from an Excel file
# The Excel file contains the raw count table for RNA-seq data
data <- readxl::read_excel("GSE130842_Count_table_Delacher_et_al_2019.xlsx")

# Extract the gene names from the first column of the dataset
gene_names <- data$ID  # 'ID' column contains gene names

# Convert the remaining columns (gene counts) to a matrix
# Skip the first column which contains gene names
data <- as.matrix(data[, -1])

# Assign gene names as row names to the count matrix
rownames(data) <- gene_names

# Subset the data for specific columns (samples)
# Columns 33:36 and 41:44 represent selected samples for analysis
data <- data[, c(33:36, 41:44)]

# Read the metadata file that contains information about the samples
# Metadata contains columns describing conditions and replicates
metadata <- utils::read.csv("GSE130842_Metadata.csv") 

# Subset relevant columns from the metadata (conditions and replicate number)
metadata <- metadata[, c(2:3)]

# Create a DESeq2 dataset object from the count matrix and metadata
# This dataset will be used for differential expression analysis
# The design formula (~condition) specifies that the analysis should model the 'condition' variable
dds <- DESeqDataSetFromMatrix(countData = data, 
                              colData = metadata,
                              design = ~condition)

# Estimate the size factors for normalization of the data
# Size factors are used to normalize the sequencing depth across samples
dds <- estimateSizeFactors(dds)

4 Exploratory Data Analysis using pcaExplorer

# Retrieve gene annotation using the OrgDb database for *Mus musculus* (mouse)
# The annotation is matched using the "ENSEMBL" identifier.
anno_df <- pcaExplorer::get_annotation_orgdb(dds, "org.Mm.eg.db", "ENSEMBL")
# Launch the PCAExplorer application to interactively explore principal component analysis (PCA) results.
# The function `pcaExplorer()` is called with the following inputs:
# - dds: A DESeq2 dataset object containing count data and experimental metadata
# - annotation: The annotation data frame (anno_df) containing gene annotations for better interpretation
# This opens a Shiny app that allows for interactive exploration of PCA and downstream analyses.
pcaExplorer(dds = dds, annotation = anno_df)

5 Differential Gene Expression Analysis using ideal and GeneTonic

# Launches the iDEAL Shiny app for interactive DE analysis
# - dds_obj: DESeq2 dataset object used for differential expression analysis
# - annotation_obj: Annotation object containing gene annotations (from `get_annotation_orgdb`)
# The `ideal()` function opens the interactive DE analysis tool that allows for visualization, interpretation, and exploration of DE results.
ideal(dds_obj = dds, annotation_obj = anno_df)
# Reading in the differential expression (DE) gene results from a pre-generated CSV file
# This file contains the DE genes and their associated statistics
de_genes <- read.csv("table_DE_results_ideal.csv")

# Converting the data into a DESeqResults object, which stores DE analysis results
# - res_de: Contains the DE genes and their statistics for downstream analysis
res_de <- DESeqResults(de_genes)
rownames(res_de) <- res_de$X  # Assign rownames for easy indexing later
colnames(res_de)[colnames(res_de) == "symbol"] <- "SYMBOL"

# Reading the functional enrichment results from a CSV file (TopGO results)
# Limiting the results to the top 500 enriched terms for further processing
topGOResults <- read.csv("table_Functional_enrichment_Results.csv")
topGOResults <- topGOResults[c(1:500),]

# This function processes the TopGO results to ensure the format is compatible
# with downstream analysis functions in `GeneTonic`.
# `shake_topGOtableResult` modifies or reorders the table as needed.
topGOResults <- shake_topGOtableResult(topGOResults)

# Aggregating scores for the gene sets and the DE genes, linking DE results with functional enrichment.
# The `get_aggrscores` function calculates aggregated enrichment scores by combining the topGO results
# and DE results (res_de) and integrating gene annotations from the annotation object (anno_df).
res_enrich <- get_aggrscores(topGOResults,
                             res_de,
                             anno_df)

# Creating a GeneTonicList (gtl) object, which consolidates all required input data for `GeneTonic`:
# - dds: DESeq2 dataset object
# - res_de: Differential expression results object
# - res_enrich: Functional enrichment scores calculated from `get_aggrscores`
# - anno_df: Gene annotation information
# The gtl object is necessary for launching the `GeneTonic()` app.
gtl <- GeneTonicList(dds, 
                     res_de, 
                     res_enrich, 
                     anno_df)
# Launch the `GeneTonic()` Shiny app, which provides an interactive platform for 
# exploring and visualizing the results of differential expression and functional enrichment analysis.
GeneTonic(gtl = gtl)

6 Functional Enrichment Result Interpretation using GeDi

GeDi::GeDi(gtl = gtl)

7 Figure Generation

This part will document the code for some of the figures included in my thesis.

# Extract the gene sets from the 'gtl' object, specifically from the enrichment results
genesets <- gtl$res_enrich

# Rename the columns in the 'genesets' data frame so that it 
# can be used directly in `GeDi`
names(genesets)[names(genesets) == "gs_id"] <- "Genesets"
names(genesets)[names(genesets) == "gs_genes"] <- "Genes"
names(genesets)[names(genesets) == "gs_description"] <- "Term"

# Prepare the gene sets for further analysis by extracting and formatting the gene information
genes <- prepareGenesetData(genesets)

# Apply a filter to exclude gene sets that have 200 or more genes
filter <- sapply(genes, function(x) length(x) >= 200)

# Remove the filtered out, large gene sets from the 'genesets' data frame
genesets <- genesets[!filter, ]

# Prepare the filtered gene sets for further analysis by reapplying the data preparation function
genes <- prepareGenesetData(genesets)

7.1 Dendrogram Example of Figure 8 and Network Example of Figure 9

# Create a copy of the 'genesets' data frame to use as example data for further analysis
example_data <- genesets

# Filter the 'example_data' to include only specific gene sets, identified by their GO terms
example_data <-
  example_data[example_data$Genesets %in% c("GO:0051988", "GO:0051987", "GO:0051315", "GO:0007094", "GO:1901970", "GO:1905820", "GO:0051984", "GO:0090267", "GO:0051255",
 "GO:1902412", "GO:0051231"),]

# Prepare the filtered gene sets for further analysis by extracting the gene information
example_genes <- prepareGenesetData(example_data)

# Calculate the Jaccard distance scores for the selected gene sets
jaccard_scores <- getJaccardMatrix(example_genes)

# Set the row and column names of the distance matrix to be the names of the gene sets
rownames(jaccard_scores) <- colnames(jaccard_scores) <- example_data$Genesets

# Generate a dendrogram 
d <- distanceDendro(jaccard_scores)

# Increase the text size of the abscissa labels for better readability and adjust the line width
d <- d + 
  theme(axis.text.x = element_text(size = 10)) +  
  geom_path(linewidth = 5)  

# Display the customized dendrogram plot
d

# Build a graph object from the adjacency matrix derived from the Jaccard scores,
# using a threshold of 0.67 to determine similarity between gene sets
g <- buildGraph(getAdjacencyMatrix(jaccard_scores, 0.67))

# Use 'visNetwork' to visualize the graph,
# set node color to blue and node border and edge color to black
visNetwork::visIgraph(g) %>%
  visNodes(color = list(
            background = "#0092AC",
            border = "#545454" ), 
           font = list(size = 20)) %>% 
  visEdges(width = 3) 

7.2 Graph Network Examples of Figure 10

# Create a copy of the 'genesets' data to be used for further analysis and prepare data
example_data <- genesets
example_genes <- prepareGenesetData(example_data)

# Calculate the Jaccard distance matrix for the gene sets
jaccard_scores <- getJaccardMatrix(example_genes)

# Set the row and column names of the Jaccard distance matrix to be the names of the gene sets
rownames(jaccard_scores) <- colnames(jaccard_scores) <- example_data$Genesets

# Perform Louvain clustering on the Jaccard distance matrix with a threshold of 0.4
louvain <- louvainClustering(jaccard_scores, 0.4)

# Perform Fuzzy clustering on the gene sets 
# Seed clusters are identified with thresholds 0.65 and 0.3, and the final clustering is done with a threshold of 0.5
fuzzy <- fuzzyClustering(seedFinding(jaccard_scores, 0.65, 0.3), 0.5)

# Build a graph object for the Louvain and Fuzzy clustering results
g_Louvain <- buildClusterGraph(louvain, 
                               example_data,
                               example_data$Genesets,
                               color_by = "Cluster")

g_Fuzzy <- buildClusterGraph(fuzzy, 
                             example_data,
                             example_data$Genesets,
                             color_by = "Cluster")

# Visualize the Louvain and Fuzzy clustering graph 
visNetwork::visIgraph(g_Louvain) %>% 
  visNodes(color = list(border = "#545454")) %>% 
  visEdges(color = list(border = "#545454"), width = 10)
visNetwork::visIgraph(g_Fuzzy) %>% 
  visNodes(color = list(border = "#545454")) %>% 
  visEdges(color = list(border = "#545454"), width = 10) 

7.3 Literature Review of Figures 16 to 18

7.3.1 Read in the data

paper_20 <- read_xlsx("LiteratureReviewResults.xlsx", 
                      sheet = "First search, 20 paper")

paper_33 <- read_xlsx("LiteratureReviewResults.xlsx", 
                      sheet = "Second search, 33 paper")

paper_44 <- read_xlsx("LiteratureReviewResults.xlsx", 
                      sheet = "Third search, 44 paper")

7.3.2 Plots on the details on the enrichment analysis

enrich20 <- data.frame(table(paper_20$`Degree of Detail on the Enrichment Method`)) 
colnames(enrich20) <- c("Detail", "Frequency")
ggplot(enrich20,aes(x = reorder(Detail,Frequency), y = Frequency, fill = Detail)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#93AA00", "#F8766D", "#D39200", "darkgrey"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Degree of Detail on the enrichment methods") +
  theme_bw(base_size = 18) +
  coord_flip() + 
  geom_text(
    aes(x = Detail, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 13))

enrich33 <- data.frame(table(paper_33$`Degree of Detail on the Enrichment Method`)) 
colnames(enrich33) <- c("Detail", "Frequency")
ggplot(enrich33,aes(x = reorder(Detail,Frequency), y = Frequency, fill = Detail)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#93AA00", "#F8766D", "#D39200", "darkgrey"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Degree of Detail on the enrichment methods") +
  theme_bw(base_size = 18) +
  coord_flip() + 
    geom_text(
    aes(x = Detail, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 16))

enrich44 <- data.frame(table(paper_44$`Degree of Detail on the Enrichment Method`)) 
colnames(enrich44) <- c("Detail", "Frequency")
ggplot(enrich44,aes(x = reorder(Detail,Frequency), y = Frequency, fill = Detail)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c( "#93AA00","#D39200", "darkgrey"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Degree of Detail on the enrichment methods") +
  theme_bw(base_size = 18) +
  coord_flip() + 
    geom_text(
    aes(x = Detail, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 25))

7.3.3 Gene Set Libraries Used

gs_Libraries20 <- paper_20$`Gene Set Library used`
gs_Libraries20 <- unlist(strsplit(gs_Libraries20, ",\\s*"))
library_20 <- data.frame(table(gs_Libraries20)) 
colnames(library_20) <- c("Library", "Frequency")
library_20$Library <- as.factor(library_20$Library)

ggplot(library_20, aes(x = reorder(Library,Frequency), y = Frequency, fill = Library)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#00C19F", "#F8766D", "#00B9E3",
                               "#D39200","darkgrey", "#93AA00"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Gene Set Library used") +
  theme_bw(base_size = 18) + 
  coord_flip() + 
    geom_text(
    aes(x = Library, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 15))

gs_Libraries33 <- paper_33$`Gene Set Library used`
gs_Libraries33 <- unlist(strsplit(gs_Libraries33, ",\\s*"))
library_33 <- data.frame(table(gs_Libraries33)) 
colnames(library_33) <- c("Library", "Frequency")
library_33$Library <- as.factor(library_33$Library)

ggplot(library_33, aes(x = reorder(Library,Frequency), y = Frequency, fill = Library)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#93AA00", "#00C19F", "#00B9E3",
                               "#F8766D", "darkgrey","#D39200"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Gene Set Library used") +
  theme_bw(base_size = 18) + 
  coord_flip() +
     geom_text(
    aes(x = Library, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 15))

gs_Libraries44 <- paper_44$`Gene Set Library used`
gs_Libraries44 <- unlist(strsplit(gs_Libraries44, ",\\s*"))
library_44 <- data.frame(table(gs_Libraries44)) 
colnames(library_44) <- c("Library", "Frequency")
library_44$Library <- as.factor(library_44$Library)

ggplot(library_44, aes(x = reorder(Library,Frequency), y = Frequency, fill = Library)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#F8766D", "#D39200", "#FF65AC", "#93AA00", "#00B9E3",  
                               "#00BA38", "darkgrey","#00C19F" ),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Gene Set Library used") +
  theme_bw(base_size = 18) + 
  coord_flip() +
     geom_text(
    aes(x = Library, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 25))

7.3.4 Software used

software20 <- paper_20$`Software used`
software20 <- unlist(strsplit(software20, ",\\s*"))
software20 <- data.frame(table(software20)) 
colnames(software20) <- c("Software", "Frequency")

ggplot(software20,aes(x = reorder(Software,Frequency), y = Frequency, fill = Software)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#FF65AC", "#F8766D", "#E18A00", "#BE9C00", "#8CAB00",
                               "#00ACFC", "#D575FE", "#24B700", "darkgrey","lightgrey",
                               "#00BE70", "#00C1AB", "#00BBDA"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Software used") +
  theme_bw(base_size = 18) + 
  coord_flip() +
     geom_text(
    aes(x = Software, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  )

software33 <- paper_33$`Software used`
software33 <- unlist(strsplit(software33, ",\\s*"))
software33 <- data.frame(table(software33)) 
colnames(software33) <- c("Software", "Frequency")

ggplot(software33,aes(x = reorder(Software,Frequency), y = Frequency, fill = Software)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#00BE70", "#D575FE", "#00C1AB", "#00BBDA","#F8766D",
                               "#E18A00", "#00ACFC", "darkgrey",  "lightgrey","#BE9C00",
                               "#8CAB00", "#24B700"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Software used") +
  theme_bw(base_size = 18) + 
  coord_flip() +
       geom_text(
    aes(x = Software, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 15))

software44 <- paper_44$`Software used`
software44 <- unlist(strsplit(software44, ",\\s*"))
software44 <- data.frame(table(software44)) 
colnames(software44) <- c("Software", "Frequency")

ggplot(software44,aes(x = reorder(Software,Frequency), y = Frequency, fill = Software)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#FF65AC", "#F8766D", "#00C1AB", "#E18A00", "#BE9C00",
                               "#D575FE", "#00BBDA", "#00ACFC", "darkgrey", "lightgrey", 
                               "#8CAB00", "#24B700","#00BE70"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Software used") +
  theme_bw(base_size = 18) + 
  coord_flip() +
       geom_text(
    aes(x = Software, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 25))

7.3.5 Function used

function20 <- data.frame(table(paper_20$`Statistical Test or Function`))
colnames(function20) <- c("Test", "Frequency")

ggplot(function20,aes(x = reorder(Test,Frequency), y = Frequency, fill = Test)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#F8766D", "darkgrey", "lightgrey"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Test/Function used") +
  theme_bw(base_size = 18) + 
  coord_flip() +
       geom_text(
    aes(x = Test, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) + 
  ylim(c(0, 16))

function33 <- data.frame(table(paper_33$`Statistical Test or Function`))
colnames(function33) <- c("Test", "Frequency")

ggplot(function33,aes(x = reorder(Test,Frequency), y = Frequency, fill = Test)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#F8766D", "#E18A00", "darkgrey", "lightgrey"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Test/Function used") +
  theme_bw(base_size = 18) + 
  coord_flip() +
         geom_text(
    aes(x = Test, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 19))

function44 <- paper_44$`Statistical Test or Function`
function44 <- unlist(strsplit(function44, ",\\s*"))
function44 <- data.frame(table(function44)) 
colnames(function44) <- c("Test", "Frequency")

ggplot(function44,aes(x = reorder(Test,Frequency), y = Frequency, fill = Test)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#F8766D", "#8CAB00", "#E18A00", "#00ACFC",
                               "darkgrey", "lightgrey", "#BE9C00"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Test/Function used") +
  theme_bw(base_size = 18) + 
  coord_flip() +
         geom_text(
    aes(x = Test, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 25))

7.3.6 Summary as a Table

table20 <- data.frame(table(paper_20$`Table of Results provided`))
colnames(table20) <- c("Table", "Frequency")
ggplot(table20,aes(x = reorder(Table,Frequency), y = Frequency, fill = Table)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c( "#D39200","darkgrey", "#93AA00"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Results presented as Table") +
  theme_bw(base_size = 18) +
  coord_flip() +
         geom_text(
    aes(x = Table, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  )

table33 <- data.frame(table(paper_33$`Table of Results provided`))
colnames(table33) <- c("Table", "Frequency")
ggplot(table33,aes(x = reorder(Table,Frequency), y = Frequency, fill = Table)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c( "#D39200","darkgrey", "#93AA00"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Results presented as Table") +
  theme_bw(base_size = 18) +
  coord_flip() +
           geom_text(
    aes(x = Table, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 15))

table44 <- data.frame(table(paper_44$`Table of Results provided`))
colnames(table44) <- c("Table", "Frequency")
ggplot(table44,aes(x = reorder(Table,Frequency), y = Frequency, fill = Table)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c( "#D39200","darkgrey", "#93AA00"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Results presented as Table") +
  theme_bw(base_size = 18) +
  coord_flip() +
           geom_text(
    aes(x = Table, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 25))

7.3.7 Summary presented visually

visual20 <- paper_20$Visualisation
visual20 <- unlist(strsplit(visual20, ",\\s*"))
visual20 <- data.frame(table(visual20)) 
colnames(visual20) <- c("Visualization", "Frequency")

ggplot(visual20,aes(x = reorder(Visualization,Frequency), y = Frequency, fill = Visualization)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#F8766D", "#E18A00", "#FF65AC", "#BE9C00", "#00BBDA",
                               "#8CAB00", "#00ACFC", "#24B700", "darkgrey",
                                "#00C1AB" ),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Type of Visualization") +
  theme_bw(base_size = 18) + 
  coord_flip() +
           geom_text(
    aes(x = Visualization, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 14))

visual33 <- paper_33$Visualisation
visual33 <- unlist(strsplit(visual33, ",\\s*"))
visual33 <- data.frame(table(visual33)) 
colnames(visual33) <- c("Visualization", "Frequency")

ggplot(visual33,aes(x = reorder(Visualization,Frequency), y = Frequency, fill = Visualization)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#00ACFC", "#F8766D", "#00BBDA", "#E18A00", "#BE9C00",
                               "#FF65AC", "#8CAB00", "#D575FE" , "#24B700", "#8B93FF",
                               "darkgrey", "#00BE70", "#00C1AB"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Type of Visualization") +
  theme_bw(base_size = 18) + 
  coord_flip() +
    geom_text(
    aes(x = Visualization, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 15))

visual44 <- paper_44$Visualisation
visual44 <- unlist(strsplit(visual44, ",\\s*"))
visual44 <- data.frame(table(visual44)) 
colnames(visual44) <- c("Visualization", "Frequency")

ggplot(visual44,aes(x = reorder(Visualization,Frequency), y = Frequency, fill = Visualization)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#F8766D", "#00ACFC", "#FF65AC", "#00BE70", 
                               "#D575FE", "#E18A00", "#BE9C00", "#00C1AB",
                               "#00BBDA", "darkgrey", "#8CAB00" ),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Type of Visualization") +
  theme_bw(base_size = 18) + 
  coord_flip() +
    geom_text(
    aes(x = Visualization, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 25))

7.3.8 Aggregation of Results

aggregation20 <- data.frame(table(paper_20$`Aggregation of Results`))
colnames(aggregation20) <- c("Aggregation", "Frequency")

ggplot(aggregation20,aes(x = reorder(Aggregation,Frequency),
                   y = Frequency, fill = Aggregation)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c( "#93AA00", "darkgrey", "#D39200"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Aggregation on the Results performed") +
  theme_bw(base_size = 18) +
  coord_flip() +
    geom_text(
    aes(x = Aggregation, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 15))

aggregation33 <- data.frame(table(paper_33$`Aggregation of Results`))
colnames(aggregation33) <- c("Aggregation", "Frequency")

ggplot(aggregation33,aes(x = reorder(Aggregation,Frequency),
                   y = Frequency, fill = Aggregation)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#93AA00", "darkgrey", "#D39200"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Aggregation on the Results performed") +
  theme_bw(base_size = 18) +
  coord_flip() +
  geom_text(
    aes(x = Aggregation, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 15))

aggregation44 <- data.frame(table(paper_44$`Aggregation of Results`))
colnames(aggregation44) <- c("Aggregation", "Frequency")

ggplot(aggregation44,aes(x = reorder(Aggregation,Frequency),
                   y = Frequency, fill = Aggregation)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#93AA00", "darkgrey", "#D39200"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Aggregation on the Results performed") +
  theme_bw(base_size = 18) +
  coord_flip() +
  geom_text(
    aes(x = Aggregation, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 25))

7.3.9 Selection of specific Gene Sets

selection20 <- data.frame(table(paper_20$`Selection of Gene Sets`))
colnames(selection20) <- c("Selection", "Frequency")

ggplot(selection20,aes(x = reorder(Selection,Frequency), y = Frequency, fill = Selection)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("darkgrey", "#F8766D"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Only selected Gene Sets presented") +
  theme_bw(base_size = 18) + 
  coord_flip() +
  geom_text(
    aes(x = Selection, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 17))

selection33 <- data.frame(table(paper_33$`Selection of Gene Sets`))
colnames(selection33) <- c("Selection", "Frequency")

ggplot(selection33,aes(x = reorder(Selection,Frequency), y = Frequency, fill = Selection)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("darkgrey", "#F8766D"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Only selected Gene Sets presented") +
  theme_bw(base_size = 18) + 
  coord_flip() +
    geom_text(
    aes(x = Selection, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 21))

selection44 <- data.frame(table(paper_44$`Selection of Gene Sets`))
colnames(selection44) <- c("Selection", "Frequency")

ggplot(selection44,aes(x = reorder(Selection,Frequency), y = Frequency, fill = Selection)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c( "darkgrey", "#F8766D"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Only selected Gene Sets presented") +
  theme_bw(base_size = 18) + 
  coord_flip() +
    geom_text(
    aes(x = Selection, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0, 25))

7.3.10 Reason for Selection

justification20 <- data.frame(table(paper_20$`Justification of Selection`))
colnames(justification20) <- c("Justification", "Frequency")

ggplot(justification20,aes(x = reorder(Justification,Frequency), y = Frequency, fill = Justification)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("Top" = "#FF65AC", "Not applicable" = "darkgrey",
                      "Not stated" = "lightgrey", "Rich Factor" =  "#00BBDA",
                      "p value" = "#8CAB00", "Number of DEG" =  "#BE9C00", 
                      "Literature" = "#E18A00", "Highest Enrichment" = "#F8766D"),
    
  
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Justification for Selection") +
  theme_bw(base_size = 18) + 
  coord_flip() +
    geom_text(
    aes(x = Justification, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  )

justification33 <- data.frame(table(paper_33$`Justification of Selection`))
colnames(justification33) <- c("Justification", "Frequency")

ggplot(justification33,aes(x = reorder(Justification,Frequency), y = Frequency, fill = Justification)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#F8766D", "darkgrey", "lightgrey",
                               "#E18A00", "#8CAB00"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Justification for Selection") +
  theme_bw(base_size = 18) + 
  coord_flip() +
    geom_text(
    aes(x = Justification, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) +
  ylim(c(0,15))

justification44 <- paper_44$`Justification of Selection`
justification44 <- unlist(strsplit(justification44, ",\\s*"))
justification44 <- data.frame(table(justification44))
colnames(justification44) <- c("Justification", "Frequency")

ggplot(justification44,aes(x = reorder(Justification,Frequency), y = Frequency, fill = Justification)) +
  geom_bar(stat ="identity") +
  scale_fill_manual(values = c("#F8766D", "#E18A00", "#FF65AC", "darkgrey",
                               "lightgrey", "#00ACFC", "#BE9C00", "#8CAB00"),
                    aesthetics = "fill",
                    guide = F) +
  labs(x = "", title = "Justification for Selection") +
  theme_bw(base_size = 18) + 
  coord_flip() +
   geom_text(
    aes(x = Justification, y = Frequency, label = Frequency), 
    hjust = -0.5, size = 5,
    position = position_dodge(width = 1),
    inherit.aes = TRUE
  ) + 
  ylim(c(0, 25))

7.3.11 Summary Figure

columns_to_check <- c(
  "Degree of Detail on the Enrichment Method",
  "Gene Set Library used",
  "Statistical Test or Function",
  "Software used",
  "Table of Results provided",
  "Visualisation",
  "Aggregation of Results",
  "Selection of Gene Sets",
  "Justification of Selection"
)

checkPaperScore <- function(paper, columns){
  n_paper <- nrow(paper)
  summery_score <- c(rep(0, n_paper))
  
  for(i in 1:n_paper) {
  entry <- paper[i, ]
  score <- 0
  
  # Check each column for "Not stated" or "Not applicable"
  for (col in columns_to_check) {
    if(col != "Degree of Detail on the Enrichment Method"){
      if(!is.null(entry[[col]]) && !(entry[[col]] %in% c("Not stated", "Not applicable", "FALSE"))) {
        score <- score + 1
      }
    }else{
      if(!is.null(entry[[col]]) && entry[[col]] == "Detailed") {
        score <- score + 1
      }
    }
    }
  summery_score[i] <- score
  }
  return(summery_score)
}


summery_score_20 <- checkPaperScore(paper_20, columns_to_check)

summery_score_33 <- checkPaperScore(paper_33, columns_to_check)

#columns_to_check <- colnames(paper_44)[6:15]
#columns_to_check[1] <- "Details (at all) on enrichment analysis"

summery_score_44 <- checkPaperScore(paper_44, columns_to_check)

scores <- c(summery_score_20, summery_score_33, summery_score_44)
scores <- as.data.frame(scores[scores != 0])
colnames(scores)<- "Size"

p <- ggplot(scores, aes(x = .data$Size)) +
    geom_histogram(binwidth = 1, fill = "#0092AC") +
    theme_bw() +
  scale_x_continuous(limits = c(0, 9.5), breaks = 0:10) +
  xlab("Completeness Score") +
  ylab("Count")
  theme(panel.grid.major.x = element_blank(),
        axis.text = element_text(size = 5),
        axis.title.x = element_text(size = 7),
        axis.title.y = element_text(size = 7))
## List of 4
##  $ axis.title.x      :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : num 7
##   ..$ hjust        : NULL
##   ..$ vjust        : NULL
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : NULL
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi FALSE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.title.y      :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : num 7
##   ..$ hjust        : NULL
##   ..$ vjust        : NULL
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : NULL
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi FALSE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ axis.text         :List of 11
##   ..$ family       : NULL
##   ..$ face         : NULL
##   ..$ colour       : NULL
##   ..$ size         : num 5
##   ..$ hjust        : NULL
##   ..$ vjust        : NULL
##   ..$ angle        : NULL
##   ..$ lineheight   : NULL
##   ..$ margin       : NULL
##   ..$ debug        : NULL
##   ..$ inherit.blank: logi FALSE
##   ..- attr(*, "class")= chr [1:2] "element_text" "element"
##  $ panel.grid.major.x: list()
##   ..- attr(*, "class")= chr [1:2] "element_blank" "element"
##  - attr(*, "class")= chr [1:2] "theme" "gg"
##  - attr(*, "complete")= logi FALSE
##  - attr(*, "validate")= logi TRUE
p

7.4 Comparison of various Alpha paramters of Figure 37

# Filter out gene sets that have fewer than 10 associated genes
filter <- sapply(genes, function(x) length(x) >= 10)
genesets_small <- genesets[!filter, ]  
genes_small <- prepareGenesetData(genesets_small) 

# Retrieve PPI information for the data 
string_db <- getStringDB(as.numeric(getId("Mus musculus")))
anno_df <- getAnnotation(string_db)
ppi <- getPPI(genes_small, string_db, anno_df)

# Calculate the Meet-Min (MM) distances
mm <- getMeetMinMatrix(genes_small)
# Set the row and column names of the MM matrix to be the names of the gene sets
rownames(mm) <- colnames(mm) <- genesets_small$Genesets

# Create a heatmap of the MM distance matrix without plot labels
d <- distanceHeatmap(mm, plot_labels = FALSE, title = "")

# Draw the heatmap and extract the row order for consistent comparison
ht <- draw(d)

row_order <- row_order(ht)

# Calculate pMM matrices for different alpha values (0, 0.5, and 1)
pMM0 <- getpMMMatrix(genes_small, ppi, alpha = 0)   
rownames(pMM0) <- colnames(pMM0) <- genesets_small$Genesets

pMM5 <- getpMMMatrix(genes_small, ppi, alpha = 0.5)
rownames(pMM5) <- colnames(pMM5) <- genesets_small$Genesets

pMM1 <- getpMMMatrix(genes_small, ppi, alpha = 1)   
rownames(pMM1) <- colnames(pMM1) <- genesets_small$Genesets

# Create and draw a heatmap for the original MM scores, keeping row order consistent
d <- distanceHeatmap(mm[row_order, row_order], 
                     plot_labels = F,
                     cluster_rows = F,
                     cluster_columns = F,
                     title = "")
draw(d)

# Create and draw a heatmap for pMM scores with alpha = 0
d <- distanceHeatmap(pMM0[row_order, row_order],
                     plot_labels = F,
                     cluster_rows = FALSE,
                     cluster_columns = FALSE,
                     title = "")
draw(d)

# Create and draw a heatmap for pMM scores with alpha = 0.5
d <- distanceHeatmap(pMM5[row_order, row_order],
                     plot_labels = F,
                     cluster_rows = FALSE,
                     cluster_columns = FALSE,
                     title = "")
draw(d)

# Create and draw a heatmap for pMM scores with alpha = 1
d <- distanceHeatmap(pMM1[row_order, row_order],
                     plot_labels = F,
                     cluster_rows = FALSE,
                     cluster_columns = FALSE,
                     title = "")
draw(d)

7.5 Word Clouds of Figure 38

# Calculate the Gene Ontology (GO) semantic distance matrix for the gene sets
goDistances <- goDistance(genesets$Genesets, species = "org.Mm.eg.db")

# Perform fuzzy clustering on the GO distance matrix.
fuzzy_clustering <- fuzzyClustering(seedFinding(goDistances, 0.5, 0.5), 0.5)

# Extract a cluster that represent T cell-related gene sets.
# The specific cluster indices were manually determined in a running `GeDi`
tCellCluster <- unique(unlist(fuzzy_clustering[c(7, 8, 14, 17, 20, 24, 28, 30, 45, 49, 50, 58, 62, 64, 65, 70, 72, 76, 81, 85, 92, 96, 103, 105, 106, 112, 114, 121, 124)]))

# Generate a word cloud visualization for the T cell-related gene sets.
enrichmentWordcloud(example_data[tCellCluster, ])
# Extract a cluster that are related to protein membrane processes.
# Again, specific cluster indices are manually selected.
proteinMembraneCluster <- unique(unlist(fuzzy_clustering[c(5, 6, 21, 23, 35, 43, 52, 54, 57, 69, 73, 80, 88, 102, 126)]))

# Generate a word cloud visualization for the protein membrane-related gene sets.
enrichmentWordcloud(example_data[proteinMembraneCluster, ])

7.6 Clustering Results of Figures 39 to 41

# Load precomputed distance matrices for the pMM and GO distance metrics
pMMDistances <- readRDS("pMM_Distances.RDS")
goDistances <- readRDS("GODistances.RDS")

# Apply Louvain clustering algorithm to the pMM distance matrix with clustering threshold 0.5
louvainpMM <- louvainClustering(pMMDistances, 0.5)

# Build a cluster graph from the Louvain clustering results for the pMM distances
g_louvainpMM <- buildClusterGraph(louvainpMM,
                                  genesets,
                                  genesets$Genesets,
                                  color_by = "Cluster")

# Visualize the Louvain clustering graph using the `visNetwork` package
visNetwork::visIgraph(g_louvainpMM) %>% 
  visNodes(color = list(border = "#545454")) %>%
  visEdges(color = list(border = "#545454"), width = 10)
# Apply Fuzzy clustering to the pMM distance matrix and
# visualisize the results afterwards
fuzzypMM <- fuzzyClustering(seedFinding(pMMDistances, 0.5, 0.5), 0.5)

g_fuzzypMM <- buildClusterGraph(fuzzypMM,
                                genesets,
                                genesets$Genesets,
                                color_by = "Cluster")

visNetwork::visIgraph(g_fuzzypMM) %>% 
  visNodes(color = list(border = "#545454")) %>%
  visEdges(color = list(border = "#545454"), width = 5)
# Apply Louvain clustering algorithm to the GO distance matrix
# Again, visualize the results afterwards
for(i in 1:100){
  louvainGO <- louvainClustering(goDistances, 0.5)
  print(paste("Round ", i, " Number Cluster ", length(louvainGO), sep = "" ))
}
## [1] "Round 1 Number Cluster 48"
## [1] "Round 2 Number Cluster 48"
## [1] "Round 3 Number Cluster 48"
## [1] "Round 4 Number Cluster 48"
## [1] "Round 5 Number Cluster 48"
## [1] "Round 6 Number Cluster 48"
## [1] "Round 7 Number Cluster 47"
## [1] "Round 8 Number Cluster 48"
## [1] "Round 9 Number Cluster 48"
## [1] "Round 10 Number Cluster 47"
## [1] "Round 11 Number Cluster 48"
## [1] "Round 12 Number Cluster 48"
## [1] "Round 13 Number Cluster 48"
## [1] "Round 14 Number Cluster 48"
## [1] "Round 15 Number Cluster 48"
## [1] "Round 16 Number Cluster 48"
## [1] "Round 17 Number Cluster 48"
## [1] "Round 18 Number Cluster 48"
## [1] "Round 19 Number Cluster 48"
## [1] "Round 20 Number Cluster 49"
## [1] "Round 21 Number Cluster 47"
## [1] "Round 22 Number Cluster 48"
## [1] "Round 23 Number Cluster 48"
## [1] "Round 24 Number Cluster 48"
## [1] "Round 25 Number Cluster 48"
## [1] "Round 26 Number Cluster 49"
## [1] "Round 27 Number Cluster 48"
## [1] "Round 28 Number Cluster 48"
## [1] "Round 29 Number Cluster 48"
## [1] "Round 30 Number Cluster 48"
## [1] "Round 31 Number Cluster 48"
## [1] "Round 32 Number Cluster 48"
## [1] "Round 33 Number Cluster 48"
## [1] "Round 34 Number Cluster 48"
## [1] "Round 35 Number Cluster 47"
## [1] "Round 36 Number Cluster 48"
## [1] "Round 37 Number Cluster 48"
## [1] "Round 38 Number Cluster 48"
## [1] "Round 39 Number Cluster 47"
## [1] "Round 40 Number Cluster 48"
## [1] "Round 41 Number Cluster 48"
## [1] "Round 42 Number Cluster 48"
## [1] "Round 43 Number Cluster 48"
## [1] "Round 44 Number Cluster 48"
## [1] "Round 45 Number Cluster 48"
## [1] "Round 46 Number Cluster 48"
## [1] "Round 47 Number Cluster 48"
## [1] "Round 48 Number Cluster 48"
## [1] "Round 49 Number Cluster 47"
## [1] "Round 50 Number Cluster 48"
## [1] "Round 51 Number Cluster 48"
## [1] "Round 52 Number Cluster 47"
## [1] "Round 53 Number Cluster 48"
## [1] "Round 54 Number Cluster 48"
## [1] "Round 55 Number Cluster 48"
## [1] "Round 56 Number Cluster 48"
## [1] "Round 57 Number Cluster 47"
## [1] "Round 58 Number Cluster 47"
## [1] "Round 59 Number Cluster 48"
## [1] "Round 60 Number Cluster 48"
## [1] "Round 61 Number Cluster 48"
## [1] "Round 62 Number Cluster 48"
## [1] "Round 63 Number Cluster 47"
## [1] "Round 64 Number Cluster 48"
## [1] "Round 65 Number Cluster 48"
## [1] "Round 66 Number Cluster 47"
## [1] "Round 67 Number Cluster 48"
## [1] "Round 68 Number Cluster 48"
## [1] "Round 69 Number Cluster 48"
## [1] "Round 70 Number Cluster 48"
## [1] "Round 71 Number Cluster 47"
## [1] "Round 72 Number Cluster 49"
## [1] "Round 73 Number Cluster 48"
## [1] "Round 74 Number Cluster 48"
## [1] "Round 75 Number Cluster 48"
## [1] "Round 76 Number Cluster 48"
## [1] "Round 77 Number Cluster 47"
## [1] "Round 78 Number Cluster 48"
## [1] "Round 79 Number Cluster 48"
## [1] "Round 80 Number Cluster 48"
## [1] "Round 81 Number Cluster 47"
## [1] "Round 82 Number Cluster 48"
## [1] "Round 83 Number Cluster 48"
## [1] "Round 84 Number Cluster 48"
## [1] "Round 85 Number Cluster 48"
## [1] "Round 86 Number Cluster 48"
## [1] "Round 87 Number Cluster 48"
## [1] "Round 88 Number Cluster 48"
## [1] "Round 89 Number Cluster 48"
## [1] "Round 90 Number Cluster 48"
## [1] "Round 91 Number Cluster 48"
## [1] "Round 92 Number Cluster 48"
## [1] "Round 93 Number Cluster 48"
## [1] "Round 94 Number Cluster 49"
## [1] "Round 95 Number Cluster 48"
## [1] "Round 96 Number Cluster 48"
## [1] "Round 97 Number Cluster 48"
## [1] "Round 98 Number Cluster 48"
## [1] "Round 99 Number Cluster 48"
## [1] "Round 100 Number Cluster 48"
louvainGO <- louvainClustering(goDistances, 0.5)

g_louvainGO <- buildClusterGraph(louvainGO,
                                 genesets,
                                 genesets$Genesets,
                                 color_by = "Cluster")

visNetwork::visIgraph(g_louvainGO) %>% 
  visNodes(color = list(border = "#545454")) %>%
  visEdges(color = list(border = "#545454"), width = 10)

Session information

sessionInfo()
## R Under development (unstable) (2024-03-12 r86109)
## Platform: x86_64-apple-darwin20
## Running under: macOS Ventura 13.2.1
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.4-x86_64/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.4-x86_64/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.0
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: Europe/Berlin
## tzcode source: internal
## 
## attached base packages:
## [1] grid      stats4    stats     graphics  grDevices utils     datasets 
## [8] methods   base     
## 
## other attached packages:
##  [1] visNetwork_2.1.2            forcats_1.0.0              
##  [3] ggplot2_3.5.1               ComplexHeatmap_2.22.0      
##  [5] org.Mm.eg.db_3.20.0         GeDi_1.2.0                 
##  [7] readxl_1.4.3                dplyr_1.1.4                
##  [9] apeglm_1.28.0               GeneTonic_3.0.0            
## [11] ideal_2.0.0                 pcaExplorer_3.0.0          
## [13] topGO_2.58.0                SparseM_1.84-2             
## [15] GO.db_3.20.0                AnnotationDbi_1.68.0       
## [17] graph_1.84.0                DESeq2_1.46.0              
## [19] SummarizedExperiment_1.36.0 Biobase_2.66.0             
## [21] MatrixGenerics_1.18.0       matrixStats_1.4.1          
## [23] GenomicRanges_1.58.0        GenomeInfoDb_1.42.0        
## [25] IRanges_2.40.0              S4Vectors_0.44.0           
## [27] BiocGenerics_0.52.0         knitr_1.48                 
## 
## loaded via a namespace (and not attached):
##   [1] R.methodsS3_1.8.2        GSEABase_1.68.0          progress_1.2.3          
##   [4] wordcloud2_0.2.1         DT_0.33                  Biostrings_2.74.0       
##   [7] vctrs_0.6.5              ggtangle_0.0.4           digest_0.6.37           
##  [10] png_0.1-8                shape_1.4.6.1            shinyBS_0.61.1          
##  [13] registry_0.5-1           ggrepel_0.9.6            magick_2.8.5            
##  [16] MASS_7.3-61              reshape2_1.4.4           httpuv_1.6.15           
##  [19] foreach_1.5.2            qvalue_2.38.0            withr_3.0.2             
##  [22] xfun_0.49                ggfun_0.1.7              survival_3.7-0          
##  [25] memoise_2.0.1            clusterProfiler_4.14.0   gson_0.1.0              
##  [28] BiasedUrn_2.0.12         tidytree_0.4.6           GlobalOptions_0.1.2     
##  [31] gtools_3.9.5             R.oo_1.26.0              prettyunits_1.2.0       
##  [34] KEGGREST_1.46.0          promises_1.3.0           httr_1.4.7              
##  [37] restfulr_0.0.15          hash_2.2.6.3             rstudioapi_0.17.1       
##  [40] shinyAce_0.4.3           UCSC.utils_1.2.0         miniUI_0.1.1.1          
##  [43] generics_0.1.3           DOSE_4.0.0               base64enc_0.1-3         
##  [46] curl_5.2.3               zlibbioc_1.52.0          polyclip_1.10-7         
##  [49] ca_0.71.1                GenomeInfoDbData_1.2.13  SparseArray_1.6.0       
##  [52] RBGL_1.82.0              threejs_0.3.3            xtable_1.8-4            
##  [55] stringr_1.5.1            doParallel_1.0.17        evaluate_1.0.1          
##  [58] S4Arrays_1.6.0           BiocFileCache_2.14.0     hms_1.1.3               
##  [61] bookdown_0.41            colorspace_2.1-1         filelock_1.0.3          
##  [64] NLP_0.3-0                shinyWidgets_0.8.7       magrittr_2.0.3          
##  [67] Rgraphviz_2.50.0         later_1.3.2              viridis_0.6.5           
##  [70] ggtree_3.14.0            lattice_0.22-6           NMF_0.28                
##  [73] genefilter_1.88.0        XML_3.99-0.17            cowplot_1.1.3           
##  [76] pillar_1.9.0             nlme_3.1-166             iterators_1.0.14        
##  [79] gridBase_0.4-7           caTools_1.18.3           compiler_4.4.0          
##  [82] stringi_1.8.4            shinycssloaders_1.1.0    Category_2.72.0         
##  [85] TSP_1.2-4                dendextend_1.18.1        GenomicAlignments_1.42.0
##  [88] plyr_1.8.9               crayon_1.5.3             abind_1.4-8             
##  [91] BiocIO_1.16.0            ggdendro_0.2.0           gridGraphics_0.5-1      
##  [94] emdbook_1.3.13           chron_2.3-61             locfit_1.5-9.10         
##  [97] bit_4.5.0                UpSetR_1.4.0             fastmatch_1.1-4         
## [100] codetools_0.2-20         crosstalk_1.2.1          bslib_0.8.0             
## [103] slam_0.1-54              GetoptLong_1.0.5         tm_0.7-14               
## [106] plotly_4.10.4            mime_0.12                mosdef_1.2.0            
## [109] splines_4.4.0            circlize_0.4.16          Rcpp_1.0.13             
## [112] dbplyr_2.5.0             tippy_0.1.0              cellranger_1.1.0        
## [115] blob_1.2.4               utf8_1.2.4               clue_0.3-65             
## [118] fs_1.6.5                 backbone_2.1.4           IHW_1.34.0              
## [121] expm_1.0-0               ggplotify_0.1.2          sqldf_0.4-11            
## [124] tibble_3.2.1             Matrix_1.7-1             statmod_1.5.0           
## [127] tweenr_2.0.3             pkgconfig_2.0.3          pheatmap_1.0.12         
## [130] tools_4.4.0              cachem_1.1.0             RSQLite_2.3.7           
## [133] viridisLite_0.4.2        DBI_1.2.3                numDeriv_2016.8-1.1     
## [136] fastmap_1.2.0            rmarkdown_2.28           scales_1.3.0            
## [139] shinydashboard_0.7.2     Rsamtools_2.22.0         sass_0.4.9              
## [142] patchwork_1.3.0          coda_0.19-4.1            BiocManager_1.30.25     
## [145] fontawesome_0.5.2        farver_2.1.2             mgcv_1.9-1              
## [148] gsubfn_0.7               yaml_2.3.10              AnnotationForge_1.48.0  
## [151] rtracklayer_1.66.0       cli_3.6.3                purrr_1.0.2             
## [154] txdbmaker_1.2.0          webshot_0.5.5            lifecycle_1.0.4         
## [157] mvtnorm_1.3-1            rintrojs_0.3.4           BiocParallel_1.40.0     
## [160] annotate_1.84.0          gtable_0.3.6             rjson_0.2.23            
## [163] ggridges_0.5.6           parallel_4.4.0           ape_5.8                 
## [166] limma_3.62.0             jsonlite_1.8.9           colourpicker_1.3.0      
## [169] seriation_1.5.6          bitops_1.0-9             bit64_4.5.2             
## [172] assertthat_0.2.1         yulab.utils_0.1.7        BiocNeighbors_2.0.0     
## [175] proto_1.0.0              heatmaply_1.5.0          geneLenDataBase_1.42.0  
## [178] bs4Dash_2.3.4            bdsmatrix_1.3-7          highr_0.11              
## [181] jquerylib_0.1.4          GOSemSim_2.32.0          R.utils_2.12.3          
## [184] lazyeval_0.2.2           shiny_1.9.1              dynamicTreeCut_1.63-1   
## [187] htmltools_0.5.8.1        enrichplot_1.26.1        rappdirs_0.3.3          
## [190] STRINGdb_2.18.0          glue_1.8.0               httr2_1.0.5             
## [193] XVector_0.46.0           RCurl_1.98-1.16          treeio_1.30.0           
## [196] ComplexUpset_1.3.3       gridExtra_2.3            igraph_2.1.1            
## [199] R6_2.5.1                 tidyr_1.3.1              gplots_3.2.0            
## [202] fdrtool_1.2.18           labeling_0.4.3           GenomicFeatures_1.58.0  
## [205] cluster_2.1.6            rngtools_1.5.2           bbmle_1.0.25.1          
## [208] aplot_0.2.3              plotrix_3.8-4            DelayedArray_0.32.0     
## [211] tidyselect_1.2.1         GOstats_2.72.0           ggforce_0.4.2           
## [214] xml2_1.3.6               munsell_0.5.1            KernSmooth_2.23-24      
## [217] goseq_1.58.0             BiocStyle_2.34.0         data.table_1.16.2       
## [220] htmlwidgets_1.6.4        fgsea_1.32.0             RColorBrewer_1.1-3      
## [223] biomaRt_2.62.0           rlang_1.1.4              rentrez_1.2.3           
## [226] lpsymphony_1.34.0        Cairo_1.6-2              fansi_1.0.6

Bibliography

Delacher, Michael, Charles D. Imbusch, Agnes Hotz-Wagenblatt, Jan Philipp Mallm, Katharina Bauer, Malte Simon, Dania Riegel, et al. 2020. Precursors for Nonlymphoid-Tissue Treg Cells Reside in Secondary Lymphoid Organs and Are Programmed by the Transcription Factor BATF.” Immunity 52 (2): 295–312.e11. https://doi.org/10.1016/j.immuni.2019.12.002.
Ludt, Annekathrin, Arsenij Ustjanzew, Harald Binder, Konstantin Strauch, and Federico Marini. 2022. Interactive and Reproducible Workflows for Exploring and Modeling RNA-seq Data with pcaExplorer, Ideal, and GeneTonic.” Current Protocols 2 (4): 1–55. https://doi.org/10.1002/cpz1.411.
LS0tCnRpdGxlOiA+CiAgRW5oYW5jaW5nIGFuYWx5c2lzIGFuZCBpbnRlcnByZXRhdGlvbiB3b3JrZmxvd3MgZm9yIHRyYW5zY3JpcHRvbWUgZGF0YSB3aXRoIGFuIGludGVyYWN0aXZlIFIvQmlvY29uZHVjdG9yIHRvb2xraXQKYXV0aG9yOgotIG5hbWU6IEFubmVrYXRocmluIFNpbHZpYSBOZWR3ZWQKICBhZmZpbGlhdGlvbjogCiAgLSAmaWQxIEluc3RpdHV0ZSBvZiBNZWRpY2FsIEJpb3N0YXRpc3RpY3MsIEVwaWRlbWlvbG9neSBhbmQgSW5mb3JtYXRpY3MgKElNQkVJKSwgTWFpbno8YnI+CiAgZW1haWw6IGFubmVsdWR0QHVuaS1tYWluei5kZQpkYXRlOiAiYHIgQmlvY1N0eWxlOjpkb2NfZGF0ZSgpYCIKcGFja2FnZTogImByIEJpb2NTdHlsZTo6cGtnX3ZlcignR2VEaScpYCIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IGNvc21vCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCmxpbmstY2l0YXRpb25zOiB0cnVlCmJpYmxpb2dyYXBoeTogInRoZXNpc19zdXBwbGVtZW50LmJpYiIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgY2FjaGU9RkFMU0UsIGV2YWwgPSBUUlVFLCBlY2hvID0gRkFMU0V9CmxpYnJhcnkoImtuaXRyIikKb3B0c19jaHVuayRzZXQoCiAgZmlnLmFsaWduID0gImNlbnRlciIsCiAgZmlnLnNob3cgPSAiYXNpcyIsCiAgZXZhbCA9IFRSVUUsCiAgZmlnLndpZHRoID0gMTAsCiAgZmlnLmhlaWdodCA9IDcsCiAgdGlkeSA9IEZBTFNFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgc2l6ZSA9ICJzbWFsbCIsCiAgY29tbWVudCA9ICIjIyIsCiAgZWNobyA9IFRSVUUsCiAgcmVzdWx0cyA9ICJtYXJrdXAiCikKb3B0aW9ucyhyZXBsYWNlLmFzc2lnbiA9IFRSVUUsIHdpZHRoID0gODApCmBgYAoKClRoaXMgZG9jdW1lbnQgYWNjb21wYW5pZXMgbXkgUGhEIHRoZXNpcyB0aXRsZWQgIkVuaGFuY2luZyBhbmFseXNpcyBhbmQgaW50ZXJwcmV0YXRpb24gd29ya2Zsb3dzIGZvciB0cmFuc2NyaXB0b21lIGRhdGEgd2l0aCBhbiBpbnRlcmFjdGl2ZSBSIEJpb2NvbmR1Y3RvciB0b29sa2l0Ii4gVGhlIGRvY3VtZW50IHdpbGwgZm9sbG93IGFsbCB0aGUgYW5hbHlzaXMgYW5kIHN0ZXBzIGRvY3VtZW50ZWQgaW4gbXkgUGhEIHRoZXNpcyBpbiBTZWN0aW9uIDMuMy4KCiMgQWJvdXQgdGhlIGRhdGEKClRoZSBkYXRhIGlsbHVzdHJhdGVkIGluIHRoaXMgZG9jdW1lbnQgaXMgZG9jdW1lbnRlZCBpbiBkZXRhaWwgaW4gU2VjdGlvbiAzLjMuMSBvZiBteSBQaEQgdGhlc2lzLiAKClRoZSBkYXRhc2V0cyBzaG93biBpcyBhbiBSTkEtc2VxIGRhdGFzZXQsIGF2YWlsYWJsZSBhdCB0aGUgR2VuZSBFeHByZXNzaW9uIE9tbmlidXMgdW5kZXIgdGhlIGFjY2Vzc2lvbiBjb2RlIFtHU0UxMzA4NDJdKGh0dHBzOi8vd3d3Lm5jYmkueHl6L2dlby9xdWVyeS9hY2MuY2dpP2FjYz1HU0UxMzA4NDIpLgoKVGhlIGRhdGEgcmVwcmVzZW50cyBhIG1vdXNlIGRhdGEgc2V0IG9mIDU2IGRpZmZlcmVudCBzYW1wbGVzIGlzb2xhdGVkIGZyb20gdmFyaW91cyBtdXJpbmUgdGlzc3Vlcy4gSW4gdGhpcyBhbmFseXNpcywgSSB3aWxsIGZvY3VzIGluIHRoZSBLbHJnMS1uZWdhdGl2ZSBOZmlsMyhHRlApLW5lZ2F0aXZlIFRyZWdzIGFuZCBLbHJnMS1wb3NpdGl2ZSBOZmlsMyhHRlApLXBvc2l0aXZlIFRyZWdzIHNhbXBsZXMgYXMgZGlzY3Vzc2VkIHdpdGggdGhlIG9yaWdpbmFsIGF1dGhvcnMgb2YgdGhlIG1hbnVzY3JpcHQgW0BEZWxhY2hlcjIwMjBdLiBUbyBhbmFseXNlIHRoZSBkYXRhLCB0aGUgY291bnQgZGF0YSB3YXMgZG93bmxvYWRlZCBmcm9tIHRoZSBHZW5lIEV4cHJlc3Npb24gT21uaWJ1cyAoaHR0cHM6Ly93d3cubmNiaS54eXovZ2VvL3F1ZXJ5L2FjYy5jZ2k/YWNjPUdTRTEzMDg0MikuIFRoZSBjb3VudCBkYXRhIGNhbiBiZSBmb3VuZCBpbiBmaWxlICJHU0UxMzA4NDJfQ291bnRfdGFibGVfRGVsYWNoZXJfZXRfYWxfMjAxOS54bHN4Ii4gQWRkaXRpb25hbGx5LCBhIG1ldGFkYXRhIGZpbGUgd2FzIHNldCB1cCwgY29udGFpbmluZyB0aGUgc2FtcGxlIG5hbWVzLCBjb25kaXRpb25zIGFuZCByZXBsaWNhdGUgbnVtYmVycyBmb2xsb3dpbmcgdGhlIGluZm9ybWF0aW9uIG9mIHRoZSBHRU8gZW50cnkuIFRoaXMgaXMgdGhlIGZpbGUgbmFtZWQgIkdTRTEzMDg0Ml9Db3VudF90YWJsZV9EZWxhY2hlcl9ldF9hbF8yMDE5LmNzdiIKClRoZSB3b3JrZmxvdyBzaG93biBpbiB0aGlzIGRvY3VtZW50IHdpbGwgZm9sbG93IHRoZSBzdGVwcyBkZXNjcmliZWQgaW4gb3VyIG1hbnVzY3JpcHQgIkludGVyYWN0aXZlIGFuZCBSZXByb2R1Y2libGUgV29ya2Zsb3dzIGZvciBFeHBsb3JpbmcgYW5kIE1vZGVsaW5nIFJOQS1zZXEgRGF0YSB3aXRoIHBjYUV4cGxvcmVyLCBJZGVhbCwgYW5kIEdlbmVUb25pYyIgW0BMdWR0MjAyMl0uCgojIExvYWRpbmcgcmVxdWlyZWQgcGFja2FnZXMKCkZpcnN0LCBsb2FkIHRoZSBwYWNrYWdlcyByZXF1aXJlZCB0byBwZXJmb3JtIGFsbCB0aGUgYW5hbHl0aWMgc3RlcHMgcHJlc2VudGVkIGluIHRoaXMgZG9jdW1lbnQuCgpgYGB7ciBsb2FkTGlicmFyaWVzLCByZXN1bHRzPSdoaWRlJ30KbGlicmFyeSgiREVTZXEyIikKbGlicmFyeSgidG9wR08iKQpsaWJyYXJ5KCJwY2FFeHBsb3JlciIpCmxpYnJhcnkoImlkZWFsIikKbGlicmFyeSgiR2VuZVRvbmljIikKbGlicmFyeSgiYXBlZ2xtIikKbGlicmFyeSgiZHBseXIiKQpsaWJyYXJ5KCJyZWFkeGwiKQpsaWJyYXJ5KCJHZURpIikKbGlicmFyeSgib3JnLk1tLmVnLmRiIikKbGlicmFyeSgidXRpbHMiKQpsaWJyYXJ5KCJDb21wbGV4SGVhdG1hcCIpCmxpYnJhcnkoInJlYWR4bCIpCmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJkcGx5ciIpCmxpYnJhcnkoImZvcmNhdHMiKQpsaWJyYXJ5KCJ2aXNOZXR3b3JrIikKYGBgCgojIERhdGEgcHJvY2Vzc2luZwoKRmlyc3QsIHRoZSBkYXRhIHdpbGwgYmUgcHJlcHJvY2Vzc2VkIGFuZCBzYXZlZCBhcyBhbiBgREVTZXFEYXRhU2V0YCBvYmplY3QsIGFzIGRlc2NyaWJlZCBpbiBTZWN0aW9uIDMuMy4xIG9mIG15IHRoZXNpcy4KCmBgYHtyIGNyZWF0ZV9kZHN9CiMgUmVhZCB0aGUgZ2VuZSBleHByZXNzaW9uIGNvdW50IGRhdGEgZnJvbSBhbiBFeGNlbCBmaWxlCiMgVGhlIEV4Y2VsIGZpbGUgY29udGFpbnMgdGhlIHJhdyBjb3VudCB0YWJsZSBmb3IgUk5BLXNlcSBkYXRhCmRhdGEgPC0gcmVhZHhsOjpyZWFkX2V4Y2VsKCJHU0UxMzA4NDJfQ291bnRfdGFibGVfRGVsYWNoZXJfZXRfYWxfMjAxOS54bHN4IikKCiMgRXh0cmFjdCB0aGUgZ2VuZSBuYW1lcyBmcm9tIHRoZSBmaXJzdCBjb2x1bW4gb2YgdGhlIGRhdGFzZXQKZ2VuZV9uYW1lcyA8LSBkYXRhJElEICAjICdJRCcgY29sdW1uIGNvbnRhaW5zIGdlbmUgbmFtZXMKCiMgQ29udmVydCB0aGUgcmVtYWluaW5nIGNvbHVtbnMgKGdlbmUgY291bnRzKSB0byBhIG1hdHJpeAojIFNraXAgdGhlIGZpcnN0IGNvbHVtbiB3aGljaCBjb250YWlucyBnZW5lIG5hbWVzCmRhdGEgPC0gYXMubWF0cml4KGRhdGFbLCAtMV0pCgojIEFzc2lnbiBnZW5lIG5hbWVzIGFzIHJvdyBuYW1lcyB0byB0aGUgY291bnQgbWF0cml4CnJvd25hbWVzKGRhdGEpIDwtIGdlbmVfbmFtZXMKCiMgU3Vic2V0IHRoZSBkYXRhIGZvciBzcGVjaWZpYyBjb2x1bW5zIChzYW1wbGVzKQojIENvbHVtbnMgMzM6MzYgYW5kIDQxOjQ0IHJlcHJlc2VudCBzZWxlY3RlZCBzYW1wbGVzIGZvciBhbmFseXNpcwpkYXRhIDwtIGRhdGFbLCBjKDMzOjM2LCA0MTo0NCldCgojIFJlYWQgdGhlIG1ldGFkYXRhIGZpbGUgdGhhdCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgc2FtcGxlcwojIE1ldGFkYXRhIGNvbnRhaW5zIGNvbHVtbnMgZGVzY3JpYmluZyBjb25kaXRpb25zIGFuZCByZXBsaWNhdGVzCm1ldGFkYXRhIDwtIHV0aWxzOjpyZWFkLmNzdigiR1NFMTMwODQyX01ldGFkYXRhLmNzdiIpIAoKIyBTdWJzZXQgcmVsZXZhbnQgY29sdW1ucyBmcm9tIHRoZSBtZXRhZGF0YSAoY29uZGl0aW9ucyBhbmQgcmVwbGljYXRlIG51bWJlcikKbWV0YWRhdGEgPC0gbWV0YWRhdGFbLCBjKDI6MyldCgojIENyZWF0ZSBhIERFU2VxMiBkYXRhc2V0IG9iamVjdCBmcm9tIHRoZSBjb3VudCBtYXRyaXggYW5kIG1ldGFkYXRhCiMgVGhpcyBkYXRhc2V0IHdpbGwgYmUgdXNlZCBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYW5hbHlzaXMKIyBUaGUgZGVzaWduIGZvcm11bGEgKH5jb25kaXRpb24pIHNwZWNpZmllcyB0aGF0IHRoZSBhbmFseXNpcyBzaG91bGQgbW9kZWwgdGhlICdjb25kaXRpb24nIHZhcmlhYmxlCmRkcyA8LSBERVNlcURhdGFTZXRGcm9tTWF0cml4KGNvdW50RGF0YSA9IGRhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gbWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2lnbiA9IH5jb25kaXRpb24pCgojIEVzdGltYXRlIHRoZSBzaXplIGZhY3RvcnMgZm9yIG5vcm1hbGl6YXRpb24gb2YgdGhlIGRhdGEKIyBTaXplIGZhY3RvcnMgYXJlIHVzZWQgdG8gbm9ybWFsaXplIHRoZSBzZXF1ZW5jaW5nIGRlcHRoIGFjcm9zcyBzYW1wbGVzCmRkcyA8LSBlc3RpbWF0ZVNpemVGYWN0b3JzKGRkcykKYGBgCgojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgdXNpbmcgcGNhRXhwbG9yZXIgCgoKYGBge3IgYW5ub2RmfQojIFJldHJpZXZlIGdlbmUgYW5ub3RhdGlvbiB1c2luZyB0aGUgT3JnRGIgZGF0YWJhc2UgZm9yICpNdXMgbXVzY3VsdXMqIChtb3VzZSkKIyBUaGUgYW5ub3RhdGlvbiBpcyBtYXRjaGVkIHVzaW5nIHRoZSAiRU5TRU1CTCIgaWRlbnRpZmllci4KYW5ub19kZiA8LSBwY2FFeHBsb3Jlcjo6Z2V0X2Fubm90YXRpb25fb3JnZGIoZGRzLCAib3JnLk1tLmVnLmRiIiwgIkVOU0VNQkwiKQpgYGAKCgpgYGB7ciBwY2FFeHBsb3JlciwgZXZhbCA9IEZ9CiMgTGF1bmNoIHRoZSBQQ0FFeHBsb3JlciBhcHBsaWNhdGlvbiB0byBpbnRlcmFjdGl2ZWx5IGV4cGxvcmUgcHJpbmNpcGFsIGNvbXBvbmVudCBhbmFseXNpcyAoUENBKSByZXN1bHRzLgojIFRoZSBmdW5jdGlvbiBgcGNhRXhwbG9yZXIoKWAgaXMgY2FsbGVkIHdpdGggdGhlIGZvbGxvd2luZyBpbnB1dHM6CiMgLSBkZHM6IEEgREVTZXEyIGRhdGFzZXQgb2JqZWN0IGNvbnRhaW5pbmcgY291bnQgZGF0YSBhbmQgZXhwZXJpbWVudGFsIG1ldGFkYXRhCiMgLSBhbm5vdGF0aW9uOiBUaGUgYW5ub3RhdGlvbiBkYXRhIGZyYW1lIChhbm5vX2RmKSBjb250YWluaW5nIGdlbmUgYW5ub3RhdGlvbnMgZm9yIGJldHRlciBpbnRlcnByZXRhdGlvbgojIFRoaXMgb3BlbnMgYSBTaGlueSBhcHAgdGhhdCBhbGxvd3MgZm9yIGludGVyYWN0aXZlIGV4cGxvcmF0aW9uIG9mIFBDQSBhbmQgZG93bnN0cmVhbSBhbmFseXNlcy4KcGNhRXhwbG9yZXIoZGRzID0gZGRzLCBhbm5vdGF0aW9uID0gYW5ub19kZikKYGBgCgoKIyBEaWZmZXJlbnRpYWwgR2VuZSBFeHByZXNzaW9uIEFuYWx5c2lzIHVzaW5nIGlkZWFsIGFuZCBHZW5lVG9uaWMKCgpgYGB7ciBkZS1pZGVhbCwgZXZhbCA9IEZ9CiMgTGF1bmNoZXMgdGhlIGlERUFMIFNoaW55IGFwcCBmb3IgaW50ZXJhY3RpdmUgREUgYW5hbHlzaXMKIyAtIGRkc19vYmo6IERFU2VxMiBkYXRhc2V0IG9iamVjdCB1c2VkIGZvciBkaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiBhbmFseXNpcwojIC0gYW5ub3RhdGlvbl9vYmo6IEFubm90YXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgZ2VuZSBhbm5vdGF0aW9ucyAoZnJvbSBgZ2V0X2Fubm90YXRpb25fb3JnZGJgKQojIFRoZSBgaWRlYWwoKWAgZnVuY3Rpb24gb3BlbnMgdGhlIGludGVyYWN0aXZlIERFIGFuYWx5c2lzIHRvb2wgdGhhdCBhbGxvd3MgZm9yIHZpc3VhbGl6YXRpb24sIGludGVycHJldGF0aW9uLCBhbmQgZXhwbG9yYXRpb24gb2YgREUgcmVzdWx0cy4KaWRlYWwoZGRzX29iaiA9IGRkcywgYW5ub3RhdGlvbl9vYmogPSBhbm5vX2RmKQpgYGAKCgoKYGBge3IgZGUtR2VuZVRvbmljfQojIFJlYWRpbmcgaW4gdGhlIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIChERSkgZ2VuZSByZXN1bHRzIGZyb20gYSBwcmUtZ2VuZXJhdGVkIENTViBmaWxlCiMgVGhpcyBmaWxlIGNvbnRhaW5zIHRoZSBERSBnZW5lcyBhbmQgdGhlaXIgYXNzb2NpYXRlZCBzdGF0aXN0aWNzCmRlX2dlbmVzIDwtIHJlYWQuY3N2KCJ0YWJsZV9ERV9yZXN1bHRzX2lkZWFsLmNzdiIpCgojIENvbnZlcnRpbmcgdGhlIGRhdGEgaW50byBhIERFU2VxUmVzdWx0cyBvYmplY3QsIHdoaWNoIHN0b3JlcyBERSBhbmFseXNpcyByZXN1bHRzCiMgLSByZXNfZGU6IENvbnRhaW5zIHRoZSBERSBnZW5lcyBhbmQgdGhlaXIgc3RhdGlzdGljcyBmb3IgZG93bnN0cmVhbSBhbmFseXNpcwpyZXNfZGUgPC0gREVTZXFSZXN1bHRzKGRlX2dlbmVzKQpyb3duYW1lcyhyZXNfZGUpIDwtIHJlc19kZSRYICAjIEFzc2lnbiByb3duYW1lcyBmb3IgZWFzeSBpbmRleGluZyBsYXRlcgpjb2xuYW1lcyhyZXNfZGUpW2NvbG5hbWVzKHJlc19kZSkgPT0gInN5bWJvbCJdIDwtICJTWU1CT0wiCgojIFJlYWRpbmcgdGhlIGZ1bmN0aW9uYWwgZW5yaWNobWVudCByZXN1bHRzIGZyb20gYSBDU1YgZmlsZSAoVG9wR08gcmVzdWx0cykKIyBMaW1pdGluZyB0aGUgcmVzdWx0cyB0byB0aGUgdG9wIDUwMCBlbnJpY2hlZCB0ZXJtcyBmb3IgZnVydGhlciBwcm9jZXNzaW5nCnRvcEdPUmVzdWx0cyA8LSByZWFkLmNzdigidGFibGVfRnVuY3Rpb25hbF9lbnJpY2htZW50X1Jlc3VsdHMuY3N2IikKdG9wR09SZXN1bHRzIDwtIHRvcEdPUmVzdWx0c1tjKDE6NTAwKSxdCgojIFRoaXMgZnVuY3Rpb24gcHJvY2Vzc2VzIHRoZSBUb3BHTyByZXN1bHRzIHRvIGVuc3VyZSB0aGUgZm9ybWF0IGlzIGNvbXBhdGlibGUKIyB3aXRoIGRvd25zdHJlYW0gYW5hbHlzaXMgZnVuY3Rpb25zIGluIGBHZW5lVG9uaWNgLgojIGBzaGFrZV90b3BHT3RhYmxlUmVzdWx0YCBtb2RpZmllcyBvciByZW9yZGVycyB0aGUgdGFibGUgYXMgbmVlZGVkLgp0b3BHT1Jlc3VsdHMgPC0gc2hha2VfdG9wR090YWJsZVJlc3VsdCh0b3BHT1Jlc3VsdHMpCgojIEFnZ3JlZ2F0aW5nIHNjb3JlcyBmb3IgdGhlIGdlbmUgc2V0cyBhbmQgdGhlIERFIGdlbmVzLCBsaW5raW5nIERFIHJlc3VsdHMgd2l0aCBmdW5jdGlvbmFsIGVucmljaG1lbnQuCiMgVGhlIGBnZXRfYWdncnNjb3Jlc2AgZnVuY3Rpb24gY2FsY3VsYXRlcyBhZ2dyZWdhdGVkIGVucmljaG1lbnQgc2NvcmVzIGJ5IGNvbWJpbmluZyB0aGUgdG9wR08gcmVzdWx0cwojIGFuZCBERSByZXN1bHRzIChyZXNfZGUpIGFuZCBpbnRlZ3JhdGluZyBnZW5lIGFubm90YXRpb25zIGZyb20gdGhlIGFubm90YXRpb24gb2JqZWN0IChhbm5vX2RmKS4KcmVzX2VucmljaCA8LSBnZXRfYWdncnNjb3Jlcyh0b3BHT1Jlc3VsdHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzX2RlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm9fZGYpCgojIENyZWF0aW5nIGEgR2VuZVRvbmljTGlzdCAoZ3RsKSBvYmplY3QsIHdoaWNoIGNvbnNvbGlkYXRlcyBhbGwgcmVxdWlyZWQgaW5wdXQgZGF0YSBmb3IgYEdlbmVUb25pY2A6CiMgLSBkZHM6IERFU2VxMiBkYXRhc2V0IG9iamVjdAojIC0gcmVzX2RlOiBEaWZmZXJlbnRpYWwgZXhwcmVzc2lvbiByZXN1bHRzIG9iamVjdAojIC0gcmVzX2VucmljaDogRnVuY3Rpb25hbCBlbnJpY2htZW50IHNjb3JlcyBjYWxjdWxhdGVkIGZyb20gYGdldF9hZ2dyc2NvcmVzYAojIC0gYW5ub19kZjogR2VuZSBhbm5vdGF0aW9uIGluZm9ybWF0aW9uCiMgVGhlIGd0bCBvYmplY3QgaXMgbmVjZXNzYXJ5IGZvciBsYXVuY2hpbmcgdGhlIGBHZW5lVG9uaWMoKWAgYXBwLgpndGwgPC0gR2VuZVRvbmljTGlzdChkZHMsIAogICAgICAgICAgICAgICAgICAgICByZXNfZGUsIAogICAgICAgICAgICAgICAgICAgICByZXNfZW5yaWNoLCAKICAgICAgICAgICAgICAgICAgICAgYW5ub19kZikKYGBgCgpgYGB7ciBMYXVuY2hHZW5lVG9uaWMsIGV2YWwgPSBGfQojIExhdW5jaCB0aGUgYEdlbmVUb25pYygpYCBTaGlueSBhcHAsIHdoaWNoIHByb3ZpZGVzIGFuIGludGVyYWN0aXZlIHBsYXRmb3JtIGZvciAKIyBleHBsb3JpbmcgYW5kIHZpc3VhbGl6aW5nIHRoZSByZXN1bHRzIG9mIGRpZmZlcmVudGlhbCBleHByZXNzaW9uIGFuZCBmdW5jdGlvbmFsIGVucmljaG1lbnQgYW5hbHlzaXMuCkdlbmVUb25pYyhndGwgPSBndGwpCmBgYAoKCiMgRnVuY3Rpb25hbCBFbnJpY2htZW50IFJlc3VsdCBJbnRlcnByZXRhdGlvbiB1c2luZyBHZURpCgoKYGBge3IgR2VEaSwgZXZhbCA9IEZ9CkdlRGk6OkdlRGkoZ3RsID0gZ3RsKQpgYGAKCgojIEZpZ3VyZSBHZW5lcmF0aW9uCgpUaGlzIHBhcnQgd2lsbCBkb2N1bWVudCB0aGUgY29kZSBmb3Igc29tZSBvZiB0aGUgZmlndXJlcyBpbmNsdWRlZCBpbiBteSB0aGVzaXMuIAoKYGBge3J9CiMgRXh0cmFjdCB0aGUgZ2VuZSBzZXRzIGZyb20gdGhlICdndGwnIG9iamVjdCwgc3BlY2lmaWNhbGx5IGZyb20gdGhlIGVucmljaG1lbnQgcmVzdWx0cwpnZW5lc2V0cyA8LSBndGwkcmVzX2VucmljaAoKIyBSZW5hbWUgdGhlIGNvbHVtbnMgaW4gdGhlICdnZW5lc2V0cycgZGF0YSBmcmFtZSBzbyB0aGF0IGl0IAojIGNhbiBiZSB1c2VkIGRpcmVjdGx5IGluIGBHZURpYApuYW1lcyhnZW5lc2V0cylbbmFtZXMoZ2VuZXNldHMpID09ICJnc19pZCJdIDwtICJHZW5lc2V0cyIKbmFtZXMoZ2VuZXNldHMpW25hbWVzKGdlbmVzZXRzKSA9PSAiZ3NfZ2VuZXMiXSA8LSAiR2VuZXMiCm5hbWVzKGdlbmVzZXRzKVtuYW1lcyhnZW5lc2V0cykgPT0gImdzX2Rlc2NyaXB0aW9uIl0gPC0gIlRlcm0iCgojIFByZXBhcmUgdGhlIGdlbmUgc2V0cyBmb3IgZnVydGhlciBhbmFseXNpcyBieSBleHRyYWN0aW5nIGFuZCBmb3JtYXR0aW5nIHRoZSBnZW5lIGluZm9ybWF0aW9uCmdlbmVzIDwtIHByZXBhcmVHZW5lc2V0RGF0YShnZW5lc2V0cykKCiMgQXBwbHkgYSBmaWx0ZXIgdG8gZXhjbHVkZSBnZW5lIHNldHMgdGhhdCBoYXZlIDIwMCBvciBtb3JlIGdlbmVzCmZpbHRlciA8LSBzYXBwbHkoZ2VuZXMsIGZ1bmN0aW9uKHgpIGxlbmd0aCh4KSA+PSAyMDApCgojIFJlbW92ZSB0aGUgZmlsdGVyZWQgb3V0LCBsYXJnZSBnZW5lIHNldHMgZnJvbSB0aGUgJ2dlbmVzZXRzJyBkYXRhIGZyYW1lCmdlbmVzZXRzIDwtIGdlbmVzZXRzWyFmaWx0ZXIsIF0KCiMgUHJlcGFyZSB0aGUgZmlsdGVyZWQgZ2VuZSBzZXRzIGZvciBmdXJ0aGVyIGFuYWx5c2lzIGJ5IHJlYXBwbHlpbmcgdGhlIGRhdGEgcHJlcGFyYXRpb24gZnVuY3Rpb24KZ2VuZXMgPC0gcHJlcGFyZUdlbmVzZXREYXRhKGdlbmVzZXRzKQpgYGAKCgojIyBEZW5kcm9ncmFtIEV4YW1wbGUgb2YgRmlndXJlIDggYW5kIE5ldHdvcmsgRXhhbXBsZSBvZiBGaWd1cmUgOQoKYGBge3J9CiMgQ3JlYXRlIGEgY29weSBvZiB0aGUgJ2dlbmVzZXRzJyBkYXRhIGZyYW1lIHRvIHVzZSBhcyBleGFtcGxlIGRhdGEgZm9yIGZ1cnRoZXIgYW5hbHlzaXMKZXhhbXBsZV9kYXRhIDwtIGdlbmVzZXRzCgojIEZpbHRlciB0aGUgJ2V4YW1wbGVfZGF0YScgdG8gaW5jbHVkZSBvbmx5IHNwZWNpZmljIGdlbmUgc2V0cywgaWRlbnRpZmllZCBieSB0aGVpciBHTyB0ZXJtcwpleGFtcGxlX2RhdGEgPC0KICBleGFtcGxlX2RhdGFbZXhhbXBsZV9kYXRhJEdlbmVzZXRzICVpbiUgYygiR086MDA1MTk4OCIsICJHTzowMDUxOTg3IiwgIkdPOjAwNTEzMTUiLCAiR086MDAwNzA5NCIsICJHTzoxOTAxOTcwIiwgIkdPOjE5MDU4MjAiLCAiR086MDA1MTk4NCIsICJHTzowMDkwMjY3IiwgIkdPOjAwNTEyNTUiLAogIkdPOjE5MDI0MTIiLCAiR086MDA1MTIzMSIpLF0KCiMgUHJlcGFyZSB0aGUgZmlsdGVyZWQgZ2VuZSBzZXRzIGZvciBmdXJ0aGVyIGFuYWx5c2lzIGJ5IGV4dHJhY3RpbmcgdGhlIGdlbmUgaW5mb3JtYXRpb24KZXhhbXBsZV9nZW5lcyA8LSBwcmVwYXJlR2VuZXNldERhdGEoZXhhbXBsZV9kYXRhKQoKIyBDYWxjdWxhdGUgdGhlIEphY2NhcmQgZGlzdGFuY2Ugc2NvcmVzIGZvciB0aGUgc2VsZWN0ZWQgZ2VuZSBzZXRzCmphY2NhcmRfc2NvcmVzIDwtIGdldEphY2NhcmRNYXRyaXgoZXhhbXBsZV9nZW5lcykKCiMgU2V0IHRoZSByb3cgYW5kIGNvbHVtbiBuYW1lcyBvZiB0aGUgZGlzdGFuY2UgbWF0cml4IHRvIGJlIHRoZSBuYW1lcyBvZiB0aGUgZ2VuZSBzZXRzCnJvd25hbWVzKGphY2NhcmRfc2NvcmVzKSA8LSBjb2xuYW1lcyhqYWNjYXJkX3Njb3JlcykgPC0gZXhhbXBsZV9kYXRhJEdlbmVzZXRzCgojIEdlbmVyYXRlIGEgZGVuZHJvZ3JhbSAKZCA8LSBkaXN0YW5jZURlbmRybyhqYWNjYXJkX3Njb3JlcykKCiMgSW5jcmVhc2UgdGhlIHRleHQgc2l6ZSBvZiB0aGUgYWJzY2lzc2EgbGFiZWxzIGZvciBiZXR0ZXIgcmVhZGFiaWxpdHkgYW5kIGFkanVzdCB0aGUgbGluZSB3aWR0aApkIDwtIGQgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApKSArICAKICBnZW9tX3BhdGgobGluZXdpZHRoID0gNSkgIAoKIyBEaXNwbGF5IHRoZSBjdXN0b21pemVkIGRlbmRyb2dyYW0gcGxvdApkCgojIEJ1aWxkIGEgZ3JhcGggb2JqZWN0IGZyb20gdGhlIGFkamFjZW5jeSBtYXRyaXggZGVyaXZlZCBmcm9tIHRoZSBKYWNjYXJkIHNjb3JlcywKIyB1c2luZyBhIHRocmVzaG9sZCBvZiAwLjY3IHRvIGRldGVybWluZSBzaW1pbGFyaXR5IGJldHdlZW4gZ2VuZSBzZXRzCmcgPC0gYnVpbGRHcmFwaChnZXRBZGphY2VuY3lNYXRyaXgoamFjY2FyZF9zY29yZXMsIDAuNjcpKQoKIyBVc2UgJ3Zpc05ldHdvcmsnIHRvIHZpc3VhbGl6ZSB0aGUgZ3JhcGgsCiMgc2V0IG5vZGUgY29sb3IgdG8gYmx1ZSBhbmQgbm9kZSBib3JkZXIgYW5kIGVkZ2UgY29sb3IgdG8gYmxhY2sKdmlzTmV0d29yazo6dmlzSWdyYXBoKGcpICU+JQogIHZpc05vZGVzKGNvbG9yID0gbGlzdCgKICAgICAgICAgICAgYmFja2dyb3VuZCA9ICIjMDA5MkFDIiwKICAgICAgICAgICAgYm9yZGVyID0gIiM1NDU0NTQiICksIAogICAgICAgICAgIGZvbnQgPSBsaXN0KHNpemUgPSAyMCkpICU+JSAKICB2aXNFZGdlcyh3aWR0aCA9IDMpIApgYGAKCgojIyBHcmFwaCBOZXR3b3JrIEV4YW1wbGVzIG9mIEZpZ3VyZSAxMAoKYGBge3J9CiMgQ3JlYXRlIGEgY29weSBvZiB0aGUgJ2dlbmVzZXRzJyBkYXRhIHRvIGJlIHVzZWQgZm9yIGZ1cnRoZXIgYW5hbHlzaXMgYW5kIHByZXBhcmUgZGF0YQpleGFtcGxlX2RhdGEgPC0gZ2VuZXNldHMKZXhhbXBsZV9nZW5lcyA8LSBwcmVwYXJlR2VuZXNldERhdGEoZXhhbXBsZV9kYXRhKQoKIyBDYWxjdWxhdGUgdGhlIEphY2NhcmQgZGlzdGFuY2UgbWF0cml4IGZvciB0aGUgZ2VuZSBzZXRzCmphY2NhcmRfc2NvcmVzIDwtIGdldEphY2NhcmRNYXRyaXgoZXhhbXBsZV9nZW5lcykKCiMgU2V0IHRoZSByb3cgYW5kIGNvbHVtbiBuYW1lcyBvZiB0aGUgSmFjY2FyZCBkaXN0YW5jZSBtYXRyaXggdG8gYmUgdGhlIG5hbWVzIG9mIHRoZSBnZW5lIHNldHMKcm93bmFtZXMoamFjY2FyZF9zY29yZXMpIDwtIGNvbG5hbWVzKGphY2NhcmRfc2NvcmVzKSA8LSBleGFtcGxlX2RhdGEkR2VuZXNldHMKCiMgUGVyZm9ybSBMb3V2YWluIGNsdXN0ZXJpbmcgb24gdGhlIEphY2NhcmQgZGlzdGFuY2UgbWF0cml4IHdpdGggYSB0aHJlc2hvbGQgb2YgMC40CmxvdXZhaW4gPC0gbG91dmFpbkNsdXN0ZXJpbmcoamFjY2FyZF9zY29yZXMsIDAuNCkKCiMgUGVyZm9ybSBGdXp6eSBjbHVzdGVyaW5nIG9uIHRoZSBnZW5lIHNldHMgCiMgU2VlZCBjbHVzdGVycyBhcmUgaWRlbnRpZmllZCB3aXRoIHRocmVzaG9sZHMgMC42NSBhbmQgMC4zLCBhbmQgdGhlIGZpbmFsIGNsdXN0ZXJpbmcgaXMgZG9uZSB3aXRoIGEgdGhyZXNob2xkIG9mIDAuNQpmdXp6eSA8LSBmdXp6eUNsdXN0ZXJpbmcoc2VlZEZpbmRpbmcoamFjY2FyZF9zY29yZXMsIDAuNjUsIDAuMyksIDAuNSkKCiMgQnVpbGQgYSBncmFwaCBvYmplY3QgZm9yIHRoZSBMb3V2YWluIGFuZCBGdXp6eSBjbHVzdGVyaW5nIHJlc3VsdHMKZ19Mb3V2YWluIDwtIGJ1aWxkQ2x1c3RlckdyYXBoKGxvdXZhaW4sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhhbXBsZV9kYXRhLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhhbXBsZV9kYXRhJEdlbmVzZXRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JfYnkgPSAiQ2x1c3RlciIpCgpnX0Z1enp5IDwtIGJ1aWxkQ2x1c3RlckdyYXBoKGZ1enp5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBleGFtcGxlX2RhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXhhbXBsZV9kYXRhJEdlbmVzZXRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yX2J5ID0gIkNsdXN0ZXIiKQoKIyBWaXN1YWxpemUgdGhlIExvdXZhaW4gYW5kIEZ1enp5IGNsdXN0ZXJpbmcgZ3JhcGggCnZpc05ldHdvcms6OnZpc0lncmFwaChnX0xvdXZhaW4pICU+JSAKICB2aXNOb2Rlcyhjb2xvciA9IGxpc3QoYm9yZGVyID0gIiM1NDU0NTQiKSkgJT4lIAogIHZpc0VkZ2VzKGNvbG9yID0gbGlzdChib3JkZXIgPSAiIzU0NTQ1NCIpLCB3aWR0aCA9IDEwKQoKdmlzTmV0d29yazo6dmlzSWdyYXBoKGdfRnV6enkpICU+JSAKICB2aXNOb2Rlcyhjb2xvciA9IGxpc3QoYm9yZGVyID0gIiM1NDU0NTQiKSkgJT4lIAogIHZpc0VkZ2VzKGNvbG9yID0gbGlzdChib3JkZXIgPSAiIzU0NTQ1NCIpLCB3aWR0aCA9IDEwKSAKYGBgCgojIyBMaXRlcmF0dXJlIFJldmlldyBvZiBGaWd1cmVzIDE2IHRvIDE4CgojIyMgUmVhZCBpbiB0aGUgZGF0YQoKYGBge3J9CnBhcGVyXzIwIDwtIHJlYWRfeGxzeCgiTGl0ZXJhdHVyZVJldmlld1Jlc3VsdHMueGxzeCIsIAogICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAiRmlyc3Qgc2VhcmNoLCAyMCBwYXBlciIpCgpwYXBlcl8zMyA8LSByZWFkX3hsc3goIkxpdGVyYXR1cmVSZXZpZXdSZXN1bHRzLnhsc3giLCAKICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gIlNlY29uZCBzZWFyY2gsIDMzIHBhcGVyIikKCnBhcGVyXzQ0IDwtIHJlYWRfeGxzeCgiTGl0ZXJhdHVyZVJldmlld1Jlc3VsdHMueGxzeCIsIAogICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAiVGhpcmQgc2VhcmNoLCA0NCBwYXBlciIpCmBgYAoKIyMjIFBsb3RzIG9uIHRoZSBkZXRhaWxzIG9uIHRoZSBlbnJpY2htZW50IGFuYWx5c2lzCgpgYGB7cn0KZW5yaWNoMjAgPC0gZGF0YS5mcmFtZSh0YWJsZShwYXBlcl8yMCRgRGVncmVlIG9mIERldGFpbCBvbiB0aGUgRW5yaWNobWVudCBNZXRob2RgKSkgCmNvbG5hbWVzKGVucmljaDIwKSA8LSBjKCJEZXRhaWwiLCAiRnJlcXVlbmN5IikKZ2dwbG90KGVucmljaDIwLGFlcyh4ID0gcmVvcmRlcihEZXRhaWwsRnJlcXVlbmN5KSwgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IERldGFpbCkpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzkzQUEwMCIsICIjRjg3NjZEIiwgIiNEMzkyMDAiLCAiZGFya2dyZXkiKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJEZWdyZWUgb2YgRGV0YWlsIG9uIHRoZSBlbnJpY2htZW50IG1ldGhvZHMiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsKICBjb29yZF9mbGlwKCkgKyAKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IERldGFpbCwgeSA9IEZyZXF1ZW5jeSwgbGFiZWwgPSBGcmVxdWVuY3kpLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApICsKICB5bGltKGMoMCwgMTMpKQoKCmVucmljaDMzIDwtIGRhdGEuZnJhbWUodGFibGUocGFwZXJfMzMkYERlZ3JlZSBvZiBEZXRhaWwgb24gdGhlIEVucmljaG1lbnQgTWV0aG9kYCkpIApjb2xuYW1lcyhlbnJpY2gzMykgPC0gYygiRGV0YWlsIiwgIkZyZXF1ZW5jeSIpCmdncGxvdChlbnJpY2gzMyxhZXMoeCA9IHJlb3JkZXIoRGV0YWlsLEZyZXF1ZW5jeSksIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBEZXRhaWwpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiM5M0FBMDAiLCAiI0Y4NzY2RCIsICIjRDM5MjAwIiwgImRhcmtncmV5IiksCiAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIiwKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IEYpICsKICBsYWJzKHggPSAiIiwgdGl0bGUgPSAiRGVncmVlIG9mIERldGFpbCBvbiB0aGUgZW5yaWNobWVudCBtZXRob2RzIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArCiAgY29vcmRfZmxpcCgpICsgCiAgICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IERldGFpbCwgeSA9IEZyZXF1ZW5jeSwgbGFiZWwgPSBGcmVxdWVuY3kpLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApICsKICB5bGltKGMoMCwgMTYpKQoKZW5yaWNoNDQgPC0gZGF0YS5mcmFtZSh0YWJsZShwYXBlcl80NCRgRGVncmVlIG9mIERldGFpbCBvbiB0aGUgRW5yaWNobWVudCBNZXRob2RgKSkgCmNvbG5hbWVzKGVucmljaDQ0KSA8LSBjKCJEZXRhaWwiLCAiRnJlcXVlbmN5IikKZ2dwbG90KGVucmljaDQ0LGFlcyh4ID0gcmVvcmRlcihEZXRhaWwsRnJlcXVlbmN5KSwgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IERldGFpbCkpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyggIiM5M0FBMDAiLCIjRDM5MjAwIiwgImRhcmtncmV5IiksCiAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIiwKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IEYpICsKICBsYWJzKHggPSAiIiwgdGl0bGUgPSAiRGVncmVlIG9mIERldGFpbCBvbiB0aGUgZW5yaWNobWVudCBtZXRob2RzIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArCiAgY29vcmRfZmxpcCgpICsgCiAgICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IERldGFpbCwgeSA9IEZyZXF1ZW5jeSwgbGFiZWwgPSBGcmVxdWVuY3kpLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApICsKICB5bGltKGMoMCwgMjUpKQoKYGBgCgojIyMgR2VuZSBTZXQgTGlicmFyaWVzIFVzZWQKCmBgYHtyfQpnc19MaWJyYXJpZXMyMCA8LSBwYXBlcl8yMCRgR2VuZSBTZXQgTGlicmFyeSB1c2VkYApnc19MaWJyYXJpZXMyMCA8LSB1bmxpc3Qoc3Ryc3BsaXQoZ3NfTGlicmFyaWVzMjAsICIsXFxzKiIpKQpsaWJyYXJ5XzIwIDwtIGRhdGEuZnJhbWUodGFibGUoZ3NfTGlicmFyaWVzMjApKSAKY29sbmFtZXMobGlicmFyeV8yMCkgPC0gYygiTGlicmFyeSIsICJGcmVxdWVuY3kiKQpsaWJyYXJ5XzIwJExpYnJhcnkgPC0gYXMuZmFjdG9yKGxpYnJhcnlfMjAkTGlicmFyeSkKCmdncGxvdChsaWJyYXJ5XzIwLCBhZXMoeCA9IHJlb3JkZXIoTGlicmFyeSxGcmVxdWVuY3kpLCB5ID0gRnJlcXVlbmN5LCBmaWxsID0gTGlicmFyeSkpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzAwQzE5RiIsICIjRjg3NjZEIiwgIiMwMEI5RTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNEMzkyMDAiLCJkYXJrZ3JleSIsICIjOTNBQTAwIiksCiAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIiwKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IEYpICsKICBsYWJzKHggPSAiIiwgdGl0bGUgPSAiR2VuZSBTZXQgTGlicmFyeSB1c2VkIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArIAogIGNvb3JkX2ZsaXAoKSArIAogICAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBMaWJyYXJ5LCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkgKwogIHlsaW0oYygwLCAxNSkpCgpnc19MaWJyYXJpZXMzMyA8LSBwYXBlcl8zMyRgR2VuZSBTZXQgTGlicmFyeSB1c2VkYApnc19MaWJyYXJpZXMzMyA8LSB1bmxpc3Qoc3Ryc3BsaXQoZ3NfTGlicmFyaWVzMzMsICIsXFxzKiIpKQpsaWJyYXJ5XzMzIDwtIGRhdGEuZnJhbWUodGFibGUoZ3NfTGlicmFyaWVzMzMpKSAKY29sbmFtZXMobGlicmFyeV8zMykgPC0gYygiTGlicmFyeSIsICJGcmVxdWVuY3kiKQpsaWJyYXJ5XzMzJExpYnJhcnkgPC0gYXMuZmFjdG9yKGxpYnJhcnlfMzMkTGlicmFyeSkKCmdncGxvdChsaWJyYXJ5XzMzLCBhZXMoeCA9IHJlb3JkZXIoTGlicmFyeSxGcmVxdWVuY3kpLCB5ID0gRnJlcXVlbmN5LCBmaWxsID0gTGlicmFyeSkpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzkzQUEwMCIsICIjMDBDMTlGIiwgIiMwMEI5RTMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNGODc2NkQiLCAiZGFya2dyZXkiLCIjRDM5MjAwIiksCiAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIiwKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IEYpICsKICBsYWJzKHggPSAiIiwgdGl0bGUgPSAiR2VuZSBTZXQgTGlicmFyeSB1c2VkIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArIAogIGNvb3JkX2ZsaXAoKSArCiAgICAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBMaWJyYXJ5LCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkgKwogIHlsaW0oYygwLCAxNSkpCgpnc19MaWJyYXJpZXM0NCA8LSBwYXBlcl80NCRgR2VuZSBTZXQgTGlicmFyeSB1c2VkYApnc19MaWJyYXJpZXM0NCA8LSB1bmxpc3Qoc3Ryc3BsaXQoZ3NfTGlicmFyaWVzNDQsICIsXFxzKiIpKQpsaWJyYXJ5XzQ0IDwtIGRhdGEuZnJhbWUodGFibGUoZ3NfTGlicmFyaWVzNDQpKSAKY29sbmFtZXMobGlicmFyeV80NCkgPC0gYygiTGlicmFyeSIsICJGcmVxdWVuY3kiKQpsaWJyYXJ5XzQ0JExpYnJhcnkgPC0gYXMuZmFjdG9yKGxpYnJhcnlfNDQkTGlicmFyeSkKCmdncGxvdChsaWJyYXJ5XzQ0LCBhZXMoeCA9IHJlb3JkZXIoTGlicmFyeSxGcmVxdWVuY3kpLCB5ID0gRnJlcXVlbmN5LCBmaWxsID0gTGlicmFyeSkpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Y4NzY2RCIsICIjRDM5MjAwIiwgIiNGRjY1QUMiLCAiIzkzQUEwMCIsICIjMDBCOUUzIiwgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiMwMEJBMzgiLCAiZGFya2dyZXkiLCIjMDBDMTlGIiApLAogICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIsCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBGKSArCiAgbGFicyh4ID0gIiIsIHRpdGxlID0gIkdlbmUgU2V0IExpYnJhcnkgdXNlZCIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxOCkgKyAKICBjb29yZF9mbGlwKCkgKwogICAgIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gTGlicmFyeSwgeSA9IEZyZXF1ZW5jeSwgbGFiZWwgPSBGcmVxdWVuY3kpLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApICsKICB5bGltKGMoMCwgMjUpKQoKYGBgCgoKIyMjIFNvZnR3YXJlIHVzZWQKCmBgYHtyfQpzb2Z0d2FyZTIwIDwtIHBhcGVyXzIwJGBTb2Z0d2FyZSB1c2VkYApzb2Z0d2FyZTIwIDwtIHVubGlzdChzdHJzcGxpdChzb2Z0d2FyZTIwLCAiLFxccyoiKSkKc29mdHdhcmUyMCA8LSBkYXRhLmZyYW1lKHRhYmxlKHNvZnR3YXJlMjApKSAKY29sbmFtZXMoc29mdHdhcmUyMCkgPC0gYygiU29mdHdhcmUiLCAiRnJlcXVlbmN5IikKCmdncGxvdChzb2Z0d2FyZTIwLGFlcyh4ID0gcmVvcmRlcihTb2Z0d2FyZSxGcmVxdWVuY3kpLCB5ID0gRnJlcXVlbmN5LCBmaWxsID0gU29mdHdhcmUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGRjY1QUMiLCAiI0Y4NzY2RCIsICIjRTE4QTAwIiwgIiNCRTlDMDAiLCAiIzhDQUIwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzAwQUNGQyIsICIjRDU3NUZFIiwgIiMyNEI3MDAiLCAiZGFya2dyZXkiLCJsaWdodGdyZXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiMwMEJFNzAiLCAiIzAwQzFBQiIsICIjMDBCQkRBIiksCiAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIiwKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IEYpICsKICBsYWJzKHggPSAiIiwgdGl0bGUgPSAiU29mdHdhcmUgdXNlZCIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxOCkgKyAKICBjb29yZF9mbGlwKCkgKwogICAgIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gU29mdHdhcmUsIHkgPSBGcmVxdWVuY3ksIGxhYmVsID0gRnJlcXVlbmN5KSwgCiAgICBoanVzdCA9IC0wLjUsIHNpemUgPSA1LAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgaW5oZXJpdC5hZXMgPSBUUlVFCiAgKQoKc29mdHdhcmUzMyA8LSBwYXBlcl8zMyRgU29mdHdhcmUgdXNlZGAKc29mdHdhcmUzMyA8LSB1bmxpc3Qoc3Ryc3BsaXQoc29mdHdhcmUzMywgIixcXHMqIikpCnNvZnR3YXJlMzMgPC0gZGF0YS5mcmFtZSh0YWJsZShzb2Z0d2FyZTMzKSkgCmNvbG5hbWVzKHNvZnR3YXJlMzMpIDwtIGMoIlNvZnR3YXJlIiwgIkZyZXF1ZW5jeSIpCgpnZ3Bsb3Qoc29mdHdhcmUzMyxhZXMoeCA9IHJlb3JkZXIoU29mdHdhcmUsRnJlcXVlbmN5KSwgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IFNvZnR3YXJlKSkgKwogIGdlb21fYmFyKHN0YXQgPSJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDBCRTcwIiwgIiNENTc1RkUiLCAiIzAwQzFBQiIsICIjMDBCQkRBIiwiI0Y4NzY2RCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI0UxOEEwMCIsICIjMDBBQ0ZDIiwgImRhcmtncmV5IiwgICJsaWdodGdyZXkiLCIjQkU5QzAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjOENBQjAwIiwgIiMyNEI3MDAiKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJTb2Z0d2FyZSB1c2VkIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArIAogIGNvb3JkX2ZsaXAoKSArCiAgICAgICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IFNvZnR3YXJlLCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkgKwogIHlsaW0oYygwLCAxNSkpCgpzb2Z0d2FyZTQ0IDwtIHBhcGVyXzQ0JGBTb2Z0d2FyZSB1c2VkYApzb2Z0d2FyZTQ0IDwtIHVubGlzdChzdHJzcGxpdChzb2Z0d2FyZTQ0LCAiLFxccyoiKSkKc29mdHdhcmU0NCA8LSBkYXRhLmZyYW1lKHRhYmxlKHNvZnR3YXJlNDQpKSAKY29sbmFtZXMoc29mdHdhcmU0NCkgPC0gYygiU29mdHdhcmUiLCAiRnJlcXVlbmN5IikKCmdncGxvdChzb2Z0d2FyZTQ0LGFlcyh4ID0gcmVvcmRlcihTb2Z0d2FyZSxGcmVxdWVuY3kpLCB5ID0gRnJlcXVlbmN5LCBmaWxsID0gU29mdHdhcmUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGRjY1QUMiLCAiI0Y4NzY2RCIsICIjMDBDMUFCIiwgIiNFMThBMDAiLCAiI0JFOUMwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI0Q1NzVGRSIsICIjMDBCQkRBIiwgIiMwMEFDRkMiLCAiZGFya2dyZXkiLCAibGlnaHRncmV5IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzhDQUIwMCIsICIjMjRCNzAwIiwiIzAwQkU3MCIpLAogICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIsCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBGKSArCiAgbGFicyh4ID0gIiIsIHRpdGxlID0gIlNvZnR3YXJlIHVzZWQiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsgCiAgY29vcmRfZmxpcCgpICsKICAgICAgIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gU29mdHdhcmUsIHkgPSBGcmVxdWVuY3ksIGxhYmVsID0gRnJlcXVlbmN5KSwgCiAgICBoanVzdCA9IC0wLjUsIHNpemUgPSA1LAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgaW5oZXJpdC5hZXMgPSBUUlVFCiAgKSArCiAgeWxpbShjKDAsIDI1KSkKCmBgYAoKIyMjIEZ1bmN0aW9uIHVzZWQKCmBgYHtyfQpmdW5jdGlvbjIwIDwtIGRhdGEuZnJhbWUodGFibGUocGFwZXJfMjAkYFN0YXRpc3RpY2FsIFRlc3Qgb3IgRnVuY3Rpb25gKSkKY29sbmFtZXMoZnVuY3Rpb24yMCkgPC0gYygiVGVzdCIsICJGcmVxdWVuY3kiKQoKZ2dwbG90KGZ1bmN0aW9uMjAsYWVzKHggPSByZW9yZGVyKFRlc3QsRnJlcXVlbmN5KSwgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IFRlc3QpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGODc2NkQiLCAiZGFya2dyZXkiLCAibGlnaHRncmV5IiksCiAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIiwKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IEYpICsKICBsYWJzKHggPSAiIiwgdGl0bGUgPSAiVGVzdC9GdW5jdGlvbiB1c2VkIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArIAogIGNvb3JkX2ZsaXAoKSArCiAgICAgICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IFRlc3QsIHkgPSBGcmVxdWVuY3ksIGxhYmVsID0gRnJlcXVlbmN5KSwgCiAgICBoanVzdCA9IC0wLjUsIHNpemUgPSA1LAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgaW5oZXJpdC5hZXMgPSBUUlVFCiAgKSArIAogIHlsaW0oYygwLCAxNikpCgpmdW5jdGlvbjMzIDwtIGRhdGEuZnJhbWUodGFibGUocGFwZXJfMzMkYFN0YXRpc3RpY2FsIFRlc3Qgb3IgRnVuY3Rpb25gKSkKY29sbmFtZXMoZnVuY3Rpb24zMykgPC0gYygiVGVzdCIsICJGcmVxdWVuY3kiKQoKZ2dwbG90KGZ1bmN0aW9uMzMsYWVzKHggPSByZW9yZGVyKFRlc3QsRnJlcXVlbmN5KSwgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IFRlc3QpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGODc2NkQiLCAiI0UxOEEwMCIsICJkYXJrZ3JleSIsICJsaWdodGdyZXkiKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJUZXN0L0Z1bmN0aW9uIHVzZWQiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsgCiAgY29vcmRfZmxpcCgpICsKICAgICAgICAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBUZXN0LCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkgKwogIHlsaW0oYygwLCAxOSkpCgoKZnVuY3Rpb240NCA8LSBwYXBlcl80NCRgU3RhdGlzdGljYWwgVGVzdCBvciBGdW5jdGlvbmAKZnVuY3Rpb240NCA8LSB1bmxpc3Qoc3Ryc3BsaXQoZnVuY3Rpb240NCwgIixcXHMqIikpCmZ1bmN0aW9uNDQgPC0gZGF0YS5mcmFtZSh0YWJsZShmdW5jdGlvbjQ0KSkgCmNvbG5hbWVzKGZ1bmN0aW9uNDQpIDwtIGMoIlRlc3QiLCAiRnJlcXVlbmN5IikKCmdncGxvdChmdW5jdGlvbjQ0LGFlcyh4ID0gcmVvcmRlcihUZXN0LEZyZXF1ZW5jeSksIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBUZXN0KSkgKwogIGdlb21fYmFyKHN0YXQgPSJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRjg3NjZEIiwgIiM4Q0FCMDAiLCAiI0UxOEEwMCIsICIjMDBBQ0ZDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkYXJrZ3JleSIsICJsaWdodGdyZXkiLCAiI0JFOUMwMCIpLAogICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIsCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBGKSArCiAgbGFicyh4ID0gIiIsIHRpdGxlID0gIlRlc3QvRnVuY3Rpb24gdXNlZCIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxOCkgKyAKICBjb29yZF9mbGlwKCkgKwogICAgICAgICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IFRlc3QsIHkgPSBGcmVxdWVuY3ksIGxhYmVsID0gRnJlcXVlbmN5KSwgCiAgICBoanVzdCA9IC0wLjUsIHNpemUgPSA1LAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgaW5oZXJpdC5hZXMgPSBUUlVFCiAgKSArCiAgeWxpbShjKDAsIDI1KSkKYGBgCgoKCiMjIyBTdW1tYXJ5IGFzIGEgVGFibGUKCmBgYHtyfQp0YWJsZTIwIDwtIGRhdGEuZnJhbWUodGFibGUocGFwZXJfMjAkYFRhYmxlIG9mIFJlc3VsdHMgcHJvdmlkZWRgKSkKY29sbmFtZXModGFibGUyMCkgPC0gYygiVGFibGUiLCAiRnJlcXVlbmN5IikKZ2dwbG90KHRhYmxlMjAsYWVzKHggPSByZW9yZGVyKFRhYmxlLEZyZXF1ZW5jeSksIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBUYWJsZSkpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYyggIiNEMzkyMDAiLCJkYXJrZ3JleSIsICIjOTNBQTAwIiksCiAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIiwKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IEYpICsKICBsYWJzKHggPSAiIiwgdGl0bGUgPSAiUmVzdWx0cyBwcmVzZW50ZWQgYXMgVGFibGUiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsKICBjb29yZF9mbGlwKCkgKwogICAgICAgICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IFRhYmxlLCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkKCnRhYmxlMzMgPC0gZGF0YS5mcmFtZSh0YWJsZShwYXBlcl8zMyRgVGFibGUgb2YgUmVzdWx0cyBwcm92aWRlZGApKQpjb2xuYW1lcyh0YWJsZTMzKSA8LSBjKCJUYWJsZSIsICJGcmVxdWVuY3kiKQpnZ3Bsb3QodGFibGUzMyxhZXMoeCA9IHJlb3JkZXIoVGFibGUsRnJlcXVlbmN5KSwgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IFRhYmxlKSkgKwogIGdlb21fYmFyKHN0YXQgPSJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCAiI0QzOTIwMCIsImRhcmtncmV5IiwgIiM5M0FBMDAiKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJSZXN1bHRzIHByZXNlbnRlZCBhcyBUYWJsZSIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxOCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgICAgICAgICAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBUYWJsZSwgeSA9IEZyZXF1ZW5jeSwgbGFiZWwgPSBGcmVxdWVuY3kpLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApICsKICB5bGltKGMoMCwgMTUpKQoKdGFibGU0NCA8LSBkYXRhLmZyYW1lKHRhYmxlKHBhcGVyXzQ0JGBUYWJsZSBvZiBSZXN1bHRzIHByb3ZpZGVkYCkpCmNvbG5hbWVzKHRhYmxlNDQpIDwtIGMoIlRhYmxlIiwgIkZyZXF1ZW5jeSIpCmdncGxvdCh0YWJsZTQ0LGFlcyh4ID0gcmVvcmRlcihUYWJsZSxGcmVxdWVuY3kpLCB5ID0gRnJlcXVlbmN5LCBmaWxsID0gVGFibGUpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoICIjRDM5MjAwIiwiZGFya2dyZXkiLCAiIzkzQUEwMCIpLAogICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIsCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBGKSArCiAgbGFicyh4ID0gIiIsIHRpdGxlID0gIlJlc3VsdHMgcHJlc2VudGVkIGFzIFRhYmxlIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArCiAgY29vcmRfZmxpcCgpICsKICAgICAgICAgICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IFRhYmxlLCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkgKwogIHlsaW0oYygwLCAyNSkpCgpgYGAKCiMjIyBTdW1tYXJ5IHByZXNlbnRlZCB2aXN1YWxseQoKYGBge3J9CnZpc3VhbDIwIDwtIHBhcGVyXzIwJFZpc3VhbGlzYXRpb24KdmlzdWFsMjAgPC0gdW5saXN0KHN0cnNwbGl0KHZpc3VhbDIwLCAiLFxccyoiKSkKdmlzdWFsMjAgPC0gZGF0YS5mcmFtZSh0YWJsZSh2aXN1YWwyMCkpIApjb2xuYW1lcyh2aXN1YWwyMCkgPC0gYygiVmlzdWFsaXphdGlvbiIsICJGcmVxdWVuY3kiKQoKZ2dwbG90KHZpc3VhbDIwLGFlcyh4ID0gcmVvcmRlcihWaXN1YWxpemF0aW9uLEZyZXF1ZW5jeSksIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBWaXN1YWxpemF0aW9uKSkgKwogIGdlb21fYmFyKHN0YXQgPSJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjRjg3NjZEIiwgIiNFMThBMDAiLCAiI0ZGNjVBQyIsICIjQkU5QzAwIiwgIiMwMEJCREEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiM4Q0FCMDAiLCAiIzAwQUNGQyIsICIjMjRCNzAwIiwgImRhcmtncmV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzAwQzFBQiIgKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJUeXBlIG9mIFZpc3VhbGl6YXRpb24iKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsgCiAgY29vcmRfZmxpcCgpICsKICAgICAgICAgICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IFZpc3VhbGl6YXRpb24sIHkgPSBGcmVxdWVuY3ksIGxhYmVsID0gRnJlcXVlbmN5KSwgCiAgICBoanVzdCA9IC0wLjUsIHNpemUgPSA1LAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgaW5oZXJpdC5hZXMgPSBUUlVFCiAgKSArCiAgeWxpbShjKDAsIDE0KSkKCnZpc3VhbDMzIDwtIHBhcGVyXzMzJFZpc3VhbGlzYXRpb24KdmlzdWFsMzMgPC0gdW5saXN0KHN0cnNwbGl0KHZpc3VhbDMzLCAiLFxccyoiKSkKdmlzdWFsMzMgPC0gZGF0YS5mcmFtZSh0YWJsZSh2aXN1YWwzMykpIApjb2xuYW1lcyh2aXN1YWwzMykgPC0gYygiVmlzdWFsaXphdGlvbiIsICJGcmVxdWVuY3kiKQoKZ2dwbG90KHZpc3VhbDMzLGFlcyh4ID0gcmVvcmRlcihWaXN1YWxpemF0aW9uLEZyZXF1ZW5jeSksIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBWaXN1YWxpemF0aW9uKSkgKwogIGdlb21fYmFyKHN0YXQgPSJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjMDBBQ0ZDIiwgIiNGODc2NkQiLCAiIzAwQkJEQSIsICIjRTE4QTAwIiwgIiNCRTlDMDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNGRjY1QUMiLCAiIzhDQUIwMCIsICIjRDU3NUZFIiAsICIjMjRCNzAwIiwgIiM4QjkzRkYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRhcmtncmV5IiwgIiMwMEJFNzAiLCAiIzAwQzFBQiIpLAogICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIsCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBGKSArCiAgbGFicyh4ID0gIiIsIHRpdGxlID0gIlR5cGUgb2YgVmlzdWFsaXphdGlvbiIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxOCkgKyAKICBjb29yZF9mbGlwKCkgKwogICAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBWaXN1YWxpemF0aW9uLCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkgKwogIHlsaW0oYygwLCAxNSkpCgp2aXN1YWw0NCA8LSBwYXBlcl80NCRWaXN1YWxpc2F0aW9uCnZpc3VhbDQ0IDwtIHVubGlzdChzdHJzcGxpdCh2aXN1YWw0NCwgIixcXHMqIikpCnZpc3VhbDQ0IDwtIGRhdGEuZnJhbWUodGFibGUodmlzdWFsNDQpKSAKY29sbmFtZXModmlzdWFsNDQpIDwtIGMoIlZpc3VhbGl6YXRpb24iLCAiRnJlcXVlbmN5IikKCmdncGxvdCh2aXN1YWw0NCxhZXMoeCA9IHJlb3JkZXIoVmlzdWFsaXphdGlvbixGcmVxdWVuY3kpLCB5ID0gRnJlcXVlbmN5LCBmaWxsID0gVmlzdWFsaXphdGlvbikpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Y4NzY2RCIsICIjMDBBQ0ZDIiwgIiNGRjY1QUMiLCAiIzAwQkU3MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNENTc1RkUiLCAiI0UxOEEwMCIsICIjQkU5QzAwIiwgIiMwMEMxQUIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiMwMEJCREEiLCAiZGFya2dyZXkiLCAiIzhDQUIwMCIgKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJUeXBlIG9mIFZpc3VhbGl6YXRpb24iKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsgCiAgY29vcmRfZmxpcCgpICsKICAgIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gVmlzdWFsaXphdGlvbiwgeSA9IEZyZXF1ZW5jeSwgbGFiZWwgPSBGcmVxdWVuY3kpLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApICsKICB5bGltKGMoMCwgMjUpKQoKYGBgCgojIyMgQWdncmVnYXRpb24gb2YgUmVzdWx0cwoKYGBge3J9CmFnZ3JlZ2F0aW9uMjAgPC0gZGF0YS5mcmFtZSh0YWJsZShwYXBlcl8yMCRgQWdncmVnYXRpb24gb2YgUmVzdWx0c2ApKQpjb2xuYW1lcyhhZ2dyZWdhdGlvbjIwKSA8LSBjKCJBZ2dyZWdhdGlvbiIsICJGcmVxdWVuY3kiKQoKZ2dwbG90KGFnZ3JlZ2F0aW9uMjAsYWVzKHggPSByZW9yZGVyKEFnZ3JlZ2F0aW9uLEZyZXF1ZW5jeSksCiAgICAgICAgICAgICAgICAgICB5ID0gRnJlcXVlbmN5LCBmaWxsID0gQWdncmVnYXRpb24pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoICIjOTNBQTAwIiwgImRhcmtncmV5IiwgIiNEMzkyMDAiKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJBZ2dyZWdhdGlvbiBvbiB0aGUgUmVzdWx0cyBwZXJmb3JtZWQiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsKICBjb29yZF9mbGlwKCkgKwogICAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBBZ2dyZWdhdGlvbiwgeSA9IEZyZXF1ZW5jeSwgbGFiZWwgPSBGcmVxdWVuY3kpLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApICsKICB5bGltKGMoMCwgMTUpKQoKYWdncmVnYXRpb24zMyA8LSBkYXRhLmZyYW1lKHRhYmxlKHBhcGVyXzMzJGBBZ2dyZWdhdGlvbiBvZiBSZXN1bHRzYCkpCmNvbG5hbWVzKGFnZ3JlZ2F0aW9uMzMpIDwtIGMoIkFnZ3JlZ2F0aW9uIiwgIkZyZXF1ZW5jeSIpCgpnZ3Bsb3QoYWdncmVnYXRpb24zMyxhZXMoeCA9IHJlb3JkZXIoQWdncmVnYXRpb24sRnJlcXVlbmN5KSwKICAgICAgICAgICAgICAgICAgIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBBZ2dyZWdhdGlvbikpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiIzkzQUEwMCIsICJkYXJrZ3JleSIsICIjRDM5MjAwIiksCiAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIiwKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IEYpICsKICBsYWJzKHggPSAiIiwgdGl0bGUgPSAiQWdncmVnYXRpb24gb24gdGhlIFJlc3VsdHMgcGVyZm9ybWVkIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArCiAgY29vcmRfZmxpcCgpICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IEFnZ3JlZ2F0aW9uLCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkgKwogIHlsaW0oYygwLCAxNSkpCgphZ2dyZWdhdGlvbjQ0IDwtIGRhdGEuZnJhbWUodGFibGUocGFwZXJfNDQkYEFnZ3JlZ2F0aW9uIG9mIFJlc3VsdHNgKSkKY29sbmFtZXMoYWdncmVnYXRpb240NCkgPC0gYygiQWdncmVnYXRpb24iLCAiRnJlcXVlbmN5IikKCmdncGxvdChhZ2dyZWdhdGlvbjQ0LGFlcyh4ID0gcmVvcmRlcihBZ2dyZWdhdGlvbixGcmVxdWVuY3kpLAogICAgICAgICAgICAgICAgICAgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IEFnZ3JlZ2F0aW9uKSkgKwogIGdlb21fYmFyKHN0YXQgPSJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTNBQTAwIiwgImRhcmtncmV5IiwgIiNEMzkyMDAiKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJBZ2dyZWdhdGlvbiBvbiB0aGUgUmVzdWx0cyBwZXJmb3JtZWQiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsKICBjb29yZF9mbGlwKCkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gQWdncmVnYXRpb24sIHkgPSBGcmVxdWVuY3ksIGxhYmVsID0gRnJlcXVlbmN5KSwgCiAgICBoanVzdCA9IC0wLjUsIHNpemUgPSA1LAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgaW5oZXJpdC5hZXMgPSBUUlVFCiAgKSArCiAgeWxpbShjKDAsIDI1KSkKYGBgCgojIyMgU2VsZWN0aW9uIG9mIHNwZWNpZmljIEdlbmUgU2V0cwoKYGBge3J9CnNlbGVjdGlvbjIwIDwtIGRhdGEuZnJhbWUodGFibGUocGFwZXJfMjAkYFNlbGVjdGlvbiBvZiBHZW5lIFNldHNgKSkKY29sbmFtZXMoc2VsZWN0aW9uMjApIDwtIGMoIlNlbGVjdGlvbiIsICJGcmVxdWVuY3kiKQoKZ2dwbG90KHNlbGVjdGlvbjIwLGFlcyh4ID0gcmVvcmRlcihTZWxlY3Rpb24sRnJlcXVlbmN5KSwgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IFNlbGVjdGlvbikpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiZGFya2dyZXkiLCAiI0Y4NzY2RCIpLAogICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIsCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBGKSArCiAgbGFicyh4ID0gIiIsIHRpdGxlID0gIk9ubHkgc2VsZWN0ZWQgR2VuZSBTZXRzIHByZXNlbnRlZCIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxOCkgKyAKICBjb29yZF9mbGlwKCkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gU2VsZWN0aW9uLCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkgKwogIHlsaW0oYygwLCAxNykpCgpzZWxlY3Rpb24zMyA8LSBkYXRhLmZyYW1lKHRhYmxlKHBhcGVyXzMzJGBTZWxlY3Rpb24gb2YgR2VuZSBTZXRzYCkpCmNvbG5hbWVzKHNlbGVjdGlvbjMzKSA8LSBjKCJTZWxlY3Rpb24iLCAiRnJlcXVlbmN5IikKCmdncGxvdChzZWxlY3Rpb24zMyxhZXMoeCA9IHJlb3JkZXIoU2VsZWN0aW9uLEZyZXF1ZW5jeSksIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBTZWxlY3Rpb24pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImRhcmtncmV5IiwgIiNGODc2NkQiKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJPbmx5IHNlbGVjdGVkIEdlbmUgU2V0cyBwcmVzZW50ZWQiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsgCiAgY29vcmRfZmxpcCgpICsKICAgIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gU2VsZWN0aW9uLCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkgKwogIHlsaW0oYygwLCAyMSkpCgpzZWxlY3Rpb240NCA8LSBkYXRhLmZyYW1lKHRhYmxlKHBhcGVyXzQ0JGBTZWxlY3Rpb24gb2YgR2VuZSBTZXRzYCkpCmNvbG5hbWVzKHNlbGVjdGlvbjQ0KSA8LSBjKCJTZWxlY3Rpb24iLCAiRnJlcXVlbmN5IikKCmdncGxvdChzZWxlY3Rpb240NCxhZXMoeCA9IHJlb3JkZXIoU2VsZWN0aW9uLEZyZXF1ZW5jeSksIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBTZWxlY3Rpb24pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoICJkYXJrZ3JleSIsICIjRjg3NjZEIiksCiAgICAgICAgICAgICAgICAgICAgYWVzdGhldGljcyA9ICJmaWxsIiwKICAgICAgICAgICAgICAgICAgICBndWlkZSA9IEYpICsKICBsYWJzKHggPSAiIiwgdGl0bGUgPSAiT25seSBzZWxlY3RlZCBHZW5lIFNldHMgcHJlc2VudGVkIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDE4KSArIAogIGNvb3JkX2ZsaXAoKSArCiAgICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IFNlbGVjdGlvbiwgeSA9IEZyZXF1ZW5jeSwgbGFiZWwgPSBGcmVxdWVuY3kpLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApICsKICB5bGltKGMoMCwgMjUpKQoKYGBgCgojIyMgUmVhc29uIGZvciBTZWxlY3Rpb24KCmBgYHtyfQpqdXN0aWZpY2F0aW9uMjAgPC0gZGF0YS5mcmFtZSh0YWJsZShwYXBlcl8yMCRgSnVzdGlmaWNhdGlvbiBvZiBTZWxlY3Rpb25gKSkKY29sbmFtZXMoanVzdGlmaWNhdGlvbjIwKSA8LSBjKCJKdXN0aWZpY2F0aW9uIiwgIkZyZXF1ZW5jeSIpCgpnZ3Bsb3QoanVzdGlmaWNhdGlvbjIwLGFlcyh4ID0gcmVvcmRlcihKdXN0aWZpY2F0aW9uLEZyZXF1ZW5jeSksIHkgPSBGcmVxdWVuY3ksIGZpbGwgPSBKdXN0aWZpY2F0aW9uKSkgKwogIGdlb21fYmFyKHN0YXQgPSJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJUb3AiID0gIiNGRjY1QUMiLCAiTm90IGFwcGxpY2FibGUiID0gImRhcmtncmV5IiwKICAgICAgICAgICAgICAgICAgICAgICJOb3Qgc3RhdGVkIiA9ICJsaWdodGdyZXkiLCAiUmljaCBGYWN0b3IiID0gICIjMDBCQkRBIiwKICAgICAgICAgICAgICAgICAgICAgICJwIHZhbHVlIiA9ICIjOENBQjAwIiwgIk51bWJlciBvZiBERUciID0gICIjQkU5QzAwIiwgCiAgICAgICAgICAgICAgICAgICAgICAiTGl0ZXJhdHVyZSIgPSAiI0UxOEEwMCIsICJIaWdoZXN0IEVucmljaG1lbnQiID0gIiNGODc2NkQiKSwKICAgIAogIAogICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIsCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBGKSArCiAgbGFicyh4ID0gIiIsIHRpdGxlID0gIkp1c3RpZmljYXRpb24gZm9yIFNlbGVjdGlvbiIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxOCkgKyAKICBjb29yZF9mbGlwKCkgKwogICAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBKdXN0aWZpY2F0aW9uLCB5ID0gRnJlcXVlbmN5LCBsYWJlbCA9IEZyZXF1ZW5jeSksIAogICAgaGp1c3QgPSAtMC41LCBzaXplID0gNSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIGluaGVyaXQuYWVzID0gVFJVRQogICkKCmp1c3RpZmljYXRpb24zMyA8LSBkYXRhLmZyYW1lKHRhYmxlKHBhcGVyXzMzJGBKdXN0aWZpY2F0aW9uIG9mIFNlbGVjdGlvbmApKQpjb2xuYW1lcyhqdXN0aWZpY2F0aW9uMzMpIDwtIGMoIkp1c3RpZmljYXRpb24iLCAiRnJlcXVlbmN5IikKCmdncGxvdChqdXN0aWZpY2F0aW9uMzMsYWVzKHggPSByZW9yZGVyKEp1c3RpZmljYXRpb24sRnJlcXVlbmN5KSwgeSA9IEZyZXF1ZW5jeSwgZmlsbCA9IEp1c3RpZmljYXRpb24pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ImlkZW50aXR5IikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNGODc2NkQiLCAiZGFya2dyZXkiLCAibGlnaHRncmV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjRTE4QTAwIiwgIiM4Q0FCMDAiKSwKICAgICAgICAgICAgICAgICAgICBhZXN0aGV0aWNzID0gImZpbGwiLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gRikgKwogIGxhYnMoeCA9ICIiLCB0aXRsZSA9ICJKdXN0aWZpY2F0aW9uIGZvciBTZWxlY3Rpb24iKSArCiAgdGhlbWVfYncoYmFzZV9zaXplID0gMTgpICsgCiAgY29vcmRfZmxpcCgpICsKICAgIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gSnVzdGlmaWNhdGlvbiwgeSA9IEZyZXF1ZW5jeSwgbGFiZWwgPSBGcmVxdWVuY3kpLCAKICAgIGhqdXN0ID0gLTAuNSwgc2l6ZSA9IDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICBpbmhlcml0LmFlcyA9IFRSVUUKICApICsKICB5bGltKGMoMCwxNSkpCgpqdXN0aWZpY2F0aW9uNDQgPC0gcGFwZXJfNDQkYEp1c3RpZmljYXRpb24gb2YgU2VsZWN0aW9uYApqdXN0aWZpY2F0aW9uNDQgPC0gdW5saXN0KHN0cnNwbGl0KGp1c3RpZmljYXRpb240NCwgIixcXHMqIikpCmp1c3RpZmljYXRpb240NCA8LSBkYXRhLmZyYW1lKHRhYmxlKGp1c3RpZmljYXRpb240NCkpCmNvbG5hbWVzKGp1c3RpZmljYXRpb240NCkgPC0gYygiSnVzdGlmaWNhdGlvbiIsICJGcmVxdWVuY3kiKQoKZ2dwbG90KGp1c3RpZmljYXRpb240NCxhZXMoeCA9IHJlb3JkZXIoSnVzdGlmaWNhdGlvbixGcmVxdWVuY3kpLCB5ID0gRnJlcXVlbmN5LCBmaWxsID0gSnVzdGlmaWNhdGlvbikpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI0Y4NzY2RCIsICIjRTE4QTAwIiwgIiNGRjY1QUMiLCAiZGFya2dyZXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImxpZ2h0Z3JleSIsICIjMDBBQ0ZDIiwgIiNCRTlDMDAiLCAiIzhDQUIwMCIpLAogICAgICAgICAgICAgICAgICAgIGFlc3RoZXRpY3MgPSAiZmlsbCIsCiAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBGKSArCiAgbGFicyh4ID0gIiIsIHRpdGxlID0gIkp1c3RpZmljYXRpb24gZm9yIFNlbGVjdGlvbiIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxOCkgKyAKICBjb29yZF9mbGlwKCkgKwogICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IEp1c3RpZmljYXRpb24sIHkgPSBGcmVxdWVuY3ksIGxhYmVsID0gRnJlcXVlbmN5KSwgCiAgICBoanVzdCA9IC0wLjUsIHNpemUgPSA1LAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgaW5oZXJpdC5hZXMgPSBUUlVFCiAgKSArIAogIHlsaW0oYygwLCAyNSkpCgpgYGAKCiMjIyBTdW1tYXJ5IEZpZ3VyZQoKYGBge3J9CmNvbHVtbnNfdG9fY2hlY2sgPC0gYygKICAiRGVncmVlIG9mIERldGFpbCBvbiB0aGUgRW5yaWNobWVudCBNZXRob2QiLAogICJHZW5lIFNldCBMaWJyYXJ5IHVzZWQiLAogICJTdGF0aXN0aWNhbCBUZXN0IG9yIEZ1bmN0aW9uIiwKICAiU29mdHdhcmUgdXNlZCIsCiAgIlRhYmxlIG9mIFJlc3VsdHMgcHJvdmlkZWQiLAogICJWaXN1YWxpc2F0aW9uIiwKICAiQWdncmVnYXRpb24gb2YgUmVzdWx0cyIsCiAgIlNlbGVjdGlvbiBvZiBHZW5lIFNldHMiLAogICJKdXN0aWZpY2F0aW9uIG9mIFNlbGVjdGlvbiIKKQoKY2hlY2tQYXBlclNjb3JlIDwtIGZ1bmN0aW9uKHBhcGVyLCBjb2x1bW5zKXsKICBuX3BhcGVyIDwtIG5yb3cocGFwZXIpCiAgc3VtbWVyeV9zY29yZSA8LSBjKHJlcCgwLCBuX3BhcGVyKSkKICAKICBmb3IoaSBpbiAxOm5fcGFwZXIpIHsKICBlbnRyeSA8LSBwYXBlcltpLCBdCiAgc2NvcmUgPC0gMAogIAogICMgQ2hlY2sgZWFjaCBjb2x1bW4gZm9yICJOb3Qgc3RhdGVkIiBvciAiTm90IGFwcGxpY2FibGUiCiAgZm9yIChjb2wgaW4gY29sdW1uc190b19jaGVjaykgewogICAgaWYoY29sICE9ICJEZWdyZWUgb2YgRGV0YWlsIG9uIHRoZSBFbnJpY2htZW50IE1ldGhvZCIpewogICAgICBpZighaXMubnVsbChlbnRyeVtbY29sXV0pICYmICEoZW50cnlbW2NvbF1dICVpbiUgYygiTm90IHN0YXRlZCIsICJOb3QgYXBwbGljYWJsZSIsICJGQUxTRSIpKSkgewogICAgICAgIHNjb3JlIDwtIHNjb3JlICsgMQogICAgICB9CiAgICB9ZWxzZXsKICAgICAgaWYoIWlzLm51bGwoZW50cnlbW2NvbF1dKSAmJiBlbnRyeVtbY29sXV0gPT0gIkRldGFpbGVkIikgewogICAgICAgIHNjb3JlIDwtIHNjb3JlICsgMQogICAgICB9CiAgICB9CiAgICB9CiAgc3VtbWVyeV9zY29yZVtpXSA8LSBzY29yZQogIH0KICByZXR1cm4oc3VtbWVyeV9zY29yZSkKfQoKCnN1bW1lcnlfc2NvcmVfMjAgPC0gY2hlY2tQYXBlclNjb3JlKHBhcGVyXzIwLCBjb2x1bW5zX3RvX2NoZWNrKQoKc3VtbWVyeV9zY29yZV8zMyA8LSBjaGVja1BhcGVyU2NvcmUocGFwZXJfMzMsIGNvbHVtbnNfdG9fY2hlY2spCgojY29sdW1uc190b19jaGVjayA8LSBjb2xuYW1lcyhwYXBlcl80NClbNjoxNV0KI2NvbHVtbnNfdG9fY2hlY2tbMV0gPC0gIkRldGFpbHMgKGF0IGFsbCkgb24gZW5yaWNobWVudCBhbmFseXNpcyIKCnN1bW1lcnlfc2NvcmVfNDQgPC0gY2hlY2tQYXBlclNjb3JlKHBhcGVyXzQ0LCBjb2x1bW5zX3RvX2NoZWNrKQoKc2NvcmVzIDwtIGMoc3VtbWVyeV9zY29yZV8yMCwgc3VtbWVyeV9zY29yZV8zMywgc3VtbWVyeV9zY29yZV80NCkKc2NvcmVzIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzW3Njb3JlcyAhPSAwXSkKY29sbmFtZXMoc2NvcmVzKTwtICJTaXplIgoKcCA8LSBnZ3Bsb3Qoc2NvcmVzLCBhZXMoeCA9IC5kYXRhJFNpemUpKSArCiAgICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGZpbGwgPSAiIzAwOTJBQyIpICsKICAgIHRoZW1lX2J3KCkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsIDkuNSksIGJyZWFrcyA9IDA6MTApICsKICB4bGFiKCJDb21wbGV0ZW5lc3MgU2NvcmUiKSArCiAgeWxhYigiQ291bnQiKQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSkKcApgYGAKCgoKCgojIyBDb21wYXJpc29uIG9mIHZhcmlvdXMgQWxwaGEgcGFyYW10ZXJzIG9mIEZpZ3VyZSAzNwoKYGBge3IgY29tcGFyaXNvbkhlYXRtYXBzfQojIEZpbHRlciBvdXQgZ2VuZSBzZXRzIHRoYXQgaGF2ZSBmZXdlciB0aGFuIDEwIGFzc29jaWF0ZWQgZ2VuZXMKZmlsdGVyIDwtIHNhcHBseShnZW5lcywgZnVuY3Rpb24oeCkgbGVuZ3RoKHgpID49IDEwKQpnZW5lc2V0c19zbWFsbCA8LSBnZW5lc2V0c1shZmlsdGVyLCBdICAKZ2VuZXNfc21hbGwgPC0gcHJlcGFyZUdlbmVzZXREYXRhKGdlbmVzZXRzX3NtYWxsKSAKCiMgUmV0cmlldmUgUFBJIGluZm9ybWF0aW9uIGZvciB0aGUgZGF0YSAKc3RyaW5nX2RiIDwtIGdldFN0cmluZ0RCKGFzLm51bWVyaWMoZ2V0SWQoIk11cyBtdXNjdWx1cyIpKSkKYW5ub19kZiA8LSBnZXRBbm5vdGF0aW9uKHN0cmluZ19kYikKcHBpIDwtIGdldFBQSShnZW5lc19zbWFsbCwgc3RyaW5nX2RiLCBhbm5vX2RmKQoKIyBDYWxjdWxhdGUgdGhlIE1lZXQtTWluIChNTSkgZGlzdGFuY2VzCm1tIDwtIGdldE1lZXRNaW5NYXRyaXgoZ2VuZXNfc21hbGwpCiMgU2V0IHRoZSByb3cgYW5kIGNvbHVtbiBuYW1lcyBvZiB0aGUgTU0gbWF0cml4IHRvIGJlIHRoZSBuYW1lcyBvZiB0aGUgZ2VuZSBzZXRzCnJvd25hbWVzKG1tKSA8LSBjb2xuYW1lcyhtbSkgPC0gZ2VuZXNldHNfc21hbGwkR2VuZXNldHMKCiMgQ3JlYXRlIGEgaGVhdG1hcCBvZiB0aGUgTU0gZGlzdGFuY2UgbWF0cml4IHdpdGhvdXQgcGxvdCBsYWJlbHMKZCA8LSBkaXN0YW5jZUhlYXRtYXAobW0sIHBsb3RfbGFiZWxzID0gRkFMU0UsIHRpdGxlID0gIiIpCgojIERyYXcgdGhlIGhlYXRtYXAgYW5kIGV4dHJhY3QgdGhlIHJvdyBvcmRlciBmb3IgY29uc2lzdGVudCBjb21wYXJpc29uCmh0IDwtIGRyYXcoZCkKcm93X29yZGVyIDwtIHJvd19vcmRlcihodCkKCiMgQ2FsY3VsYXRlIHBNTSBtYXRyaWNlcyBmb3IgZGlmZmVyZW50IGFscGhhIHZhbHVlcyAoMCwgMC41LCBhbmQgMSkKcE1NMCA8LSBnZXRwTU1NYXRyaXgoZ2VuZXNfc21hbGwsIHBwaSwgYWxwaGEgPSAwKSAgIApyb3duYW1lcyhwTU0wKSA8LSBjb2xuYW1lcyhwTU0wKSA8LSBnZW5lc2V0c19zbWFsbCRHZW5lc2V0cwoKcE1NNSA8LSBnZXRwTU1NYXRyaXgoZ2VuZXNfc21hbGwsIHBwaSwgYWxwaGEgPSAwLjUpCnJvd25hbWVzKHBNTTUpIDwtIGNvbG5hbWVzKHBNTTUpIDwtIGdlbmVzZXRzX3NtYWxsJEdlbmVzZXRzCgpwTU0xIDwtIGdldHBNTU1hdHJpeChnZW5lc19zbWFsbCwgcHBpLCBhbHBoYSA9IDEpICAgCnJvd25hbWVzKHBNTTEpIDwtIGNvbG5hbWVzKHBNTTEpIDwtIGdlbmVzZXRzX3NtYWxsJEdlbmVzZXRzCgojIENyZWF0ZSBhbmQgZHJhdyBhIGhlYXRtYXAgZm9yIHRoZSBvcmlnaW5hbCBNTSBzY29yZXMsIGtlZXBpbmcgcm93IG9yZGVyIGNvbnNpc3RlbnQKZCA8LSBkaXN0YW5jZUhlYXRtYXAobW1bcm93X29yZGVyLCByb3dfb3JkZXJdLCAKICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGLAogICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGLAogICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX2NvbHVtbnMgPSBGLAogICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICIiKQpkcmF3KGQpCgojIENyZWF0ZSBhbmQgZHJhdyBhIGhlYXRtYXAgZm9yIHBNTSBzY29yZXMgd2l0aCBhbHBoYSA9IDAKZCA8LSBkaXN0YW5jZUhlYXRtYXAocE1NMFtyb3dfb3JkZXIsIHJvd19vcmRlcl0sCiAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGFiZWxzID0gRiwKICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9yb3dzID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfY29sdW1ucyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICIiKQpkcmF3KGQpCgojIENyZWF0ZSBhbmQgZHJhdyBhIGhlYXRtYXAgZm9yIHBNTSBzY29yZXMgd2l0aCBhbHBoYSA9IDAuNQpkIDwtIGRpc3RhbmNlSGVhdG1hcChwTU01W3Jvd19vcmRlciwgcm93X29yZGVyXSwKICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGLAogICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIiIpCmRyYXcoZCkKCiMgQ3JlYXRlIGFuZCBkcmF3IGEgaGVhdG1hcCBmb3IgcE1NIHNjb3JlcyB3aXRoIGFscGhhID0gMQpkIDwtIGRpc3RhbmNlSGVhdG1hcChwTU0xW3Jvd19vcmRlciwgcm93X29yZGVyXSwKICAgICAgICAgICAgICAgICAgICAgcGxvdF9sYWJlbHMgPSBGLAogICAgICAgICAgICAgICAgICAgICBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIiIpCmRyYXcoZCkKCmBgYAoKIyMgV29yZCBDbG91ZHMgb2YgRmlndXJlIDM4CgpgYGB7cn0KIyBDYWxjdWxhdGUgdGhlIEdlbmUgT250b2xvZ3kgKEdPKSBzZW1hbnRpYyBkaXN0YW5jZSBtYXRyaXggZm9yIHRoZSBnZW5lIHNldHMKZ29EaXN0YW5jZXMgPC0gZ29EaXN0YW5jZShnZW5lc2V0cyRHZW5lc2V0cywgc3BlY2llcyA9ICJvcmcuTW0uZWcuZGIiKQoKIyBQZXJmb3JtIGZ1enp5IGNsdXN0ZXJpbmcgb24gdGhlIEdPIGRpc3RhbmNlIG1hdHJpeC4KZnV6enlfY2x1c3RlcmluZyA8LSBmdXp6eUNsdXN0ZXJpbmcoc2VlZEZpbmRpbmcoZ29EaXN0YW5jZXMsIDAuNSwgMC41KSwgMC41KQoKIyBFeHRyYWN0IGEgY2x1c3RlciB0aGF0IHJlcHJlc2VudCBUIGNlbGwtcmVsYXRlZCBnZW5lIHNldHMuCiMgVGhlIHNwZWNpZmljIGNsdXN0ZXIgaW5kaWNlcyB3ZXJlIG1hbnVhbGx5IGRldGVybWluZWQgaW4gYSBydW5uaW5nIGBHZURpYAp0Q2VsbENsdXN0ZXIgPC0gdW5pcXVlKHVubGlzdChmdXp6eV9jbHVzdGVyaW5nW2MoNywgOCwgMTQsIDE3LCAyMCwgMjQsIDI4LCAzMCwgNDUsIDQ5LCA1MCwgNTgsIDYyLCA2NCwgNjUsIDcwLCA3MiwgNzYsIDgxLCA4NSwgOTIsIDk2LCAxMDMsIDEwNSwgMTA2LCAxMTIsIDExNCwgMTIxLCAxMjQpXSkpCgojIEdlbmVyYXRlIGEgd29yZCBjbG91ZCB2aXN1YWxpemF0aW9uIGZvciB0aGUgVCBjZWxsLXJlbGF0ZWQgZ2VuZSBzZXRzLgplbnJpY2htZW50V29yZGNsb3VkKGV4YW1wbGVfZGF0YVt0Q2VsbENsdXN0ZXIsIF0pCgojIEV4dHJhY3QgYSBjbHVzdGVyIHRoYXQgYXJlIHJlbGF0ZWQgdG8gcHJvdGVpbiBtZW1icmFuZSBwcm9jZXNzZXMuCiMgQWdhaW4sIHNwZWNpZmljIGNsdXN0ZXIgaW5kaWNlcyBhcmUgbWFudWFsbHkgc2VsZWN0ZWQuCnByb3RlaW5NZW1icmFuZUNsdXN0ZXIgPC0gdW5pcXVlKHVubGlzdChmdXp6eV9jbHVzdGVyaW5nW2MoNSwgNiwgMjEsIDIzLCAzNSwgNDMsIDUyLCA1NCwgNTcsIDY5LCA3MywgODAsIDg4LCAxMDIsIDEyNildKSkKCiMgR2VuZXJhdGUgYSB3b3JkIGNsb3VkIHZpc3VhbGl6YXRpb24gZm9yIHRoZSBwcm90ZWluIG1lbWJyYW5lLXJlbGF0ZWQgZ2VuZSBzZXRzLgplbnJpY2htZW50V29yZGNsb3VkKGV4YW1wbGVfZGF0YVtwcm90ZWluTWVtYnJhbmVDbHVzdGVyLCBdKQpgYGAKCiMjIENsdXN0ZXJpbmcgUmVzdWx0cyBvZiBGaWd1cmVzIDM5IHRvIDQxCgpgYGB7cn0KIyBMb2FkIHByZWNvbXB1dGVkIGRpc3RhbmNlIG1hdHJpY2VzIGZvciB0aGUgcE1NIGFuZCBHTyBkaXN0YW5jZSBtZXRyaWNzCnBNTURpc3RhbmNlcyA8LSByZWFkUkRTKCJwTU1fRGlzdGFuY2VzLlJEUyIpCmdvRGlzdGFuY2VzIDwtIHJlYWRSRFMoIkdPRGlzdGFuY2VzLlJEUyIpCgojIEFwcGx5IExvdXZhaW4gY2x1c3RlcmluZyBhbGdvcml0aG0gdG8gdGhlIHBNTSBkaXN0YW5jZSBtYXRyaXggd2l0aCBjbHVzdGVyaW5nIHRocmVzaG9sZCAwLjUKbG91dmFpbnBNTSA8LSBsb3V2YWluQ2x1c3RlcmluZyhwTU1EaXN0YW5jZXMsIDAuNSkKCiMgQnVpbGQgYSBjbHVzdGVyIGdyYXBoIGZyb20gdGhlIExvdXZhaW4gY2x1c3RlcmluZyByZXN1bHRzIGZvciB0aGUgcE1NIGRpc3RhbmNlcwpnX2xvdXZhaW5wTU0gPC0gYnVpbGRDbHVzdGVyR3JhcGgobG91dmFpbnBNTSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVzZXRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZXNldHMkR2VuZXNldHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9ieSA9ICJDbHVzdGVyIikKCiMgVmlzdWFsaXplIHRoZSBMb3V2YWluIGNsdXN0ZXJpbmcgZ3JhcGggdXNpbmcgdGhlIGB2aXNOZXR3b3JrYCBwYWNrYWdlCnZpc05ldHdvcms6OnZpc0lncmFwaChnX2xvdXZhaW5wTU0pICU+JSAKICB2aXNOb2Rlcyhjb2xvciA9IGxpc3QoYm9yZGVyID0gIiM1NDU0NTQiKSkgJT4lCiAgdmlzRWRnZXMoY29sb3IgPSBsaXN0KGJvcmRlciA9ICIjNTQ1NDU0IiksIHdpZHRoID0gMTApCgojIEFwcGx5IEZ1enp5IGNsdXN0ZXJpbmcgdG8gdGhlIHBNTSBkaXN0YW5jZSBtYXRyaXggYW5kCiMgdmlzdWFsaXNpemUgdGhlIHJlc3VsdHMgYWZ0ZXJ3YXJkcwpmdXp6eXBNTSA8LSBmdXp6eUNsdXN0ZXJpbmcoc2VlZEZpbmRpbmcocE1NRGlzdGFuY2VzLCAwLjUsIDAuNSksIDAuNSkKCmdfZnV6enlwTU0gPC0gYnVpbGRDbHVzdGVyR3JhcGgoZnV6enlwTU0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZXNldHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZXNldHMkR2VuZXNldHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JfYnkgPSAiQ2x1c3RlciIpCgp2aXNOZXR3b3JrOjp2aXNJZ3JhcGgoZ19mdXp6eXBNTSkgJT4lIAogIHZpc05vZGVzKGNvbG9yID0gbGlzdChib3JkZXIgPSAiIzU0NTQ1NCIpKSAlPiUKICB2aXNFZGdlcyhjb2xvciA9IGxpc3QoYm9yZGVyID0gIiM1NDU0NTQiKSwgd2lkdGggPSA1KQoKIyBBcHBseSBMb3V2YWluIGNsdXN0ZXJpbmcgYWxnb3JpdGhtIHRvIHRoZSBHTyBkaXN0YW5jZSBtYXRyaXgKIyBBZ2FpbiwgdmlzdWFsaXplIHRoZSByZXN1bHRzIGFmdGVyd2FyZHMKZm9yKGkgaW4gMToxMDApewogIGxvdXZhaW5HTyA8LSBsb3V2YWluQ2x1c3RlcmluZyhnb0Rpc3RhbmNlcywgMC41KQogIHByaW50KHBhc3RlKCJSb3VuZCAiLCBpLCAiIE51bWJlciBDbHVzdGVyICIsIGxlbmd0aChsb3V2YWluR08pLCBzZXAgPSAiIiApKQp9Cgpsb3V2YWluR08gPC0gbG91dmFpbkNsdXN0ZXJpbmcoZ29EaXN0YW5jZXMsIDAuNSkKCmdfbG91dmFpbkdPIDwtIGJ1aWxkQ2x1c3RlckdyYXBoKGxvdXZhaW5HTywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VuZXNldHMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlbmVzZXRzJEdlbmVzZXRzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcl9ieSA9ICJDbHVzdGVyIikKCnZpc05ldHdvcms6OnZpc0lncmFwaChnX2xvdXZhaW5HTykgJT4lIAogIHZpc05vZGVzKGNvbG9yID0gbGlzdChib3JkZXIgPSAiIzU0NTQ1NCIpKSAlPiUKICB2aXNFZGdlcyhjb2xvciA9IGxpc3QoYm9yZGVyID0gIiM1NDU0NTQiKSwgd2lkdGggPSAxMCkKYGBgCgoKCgojIFNlc3Npb24gaW5mb3JtYXRpb24gey19CgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAKCgojIEJpYmxpb2dyYXBoeSB7LX0K